xref: /onnv-gate/usr/src/uts/common/io/comstar/stmf/stmf.c (revision 7979:1014d5427acf)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
227836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <sys/conf.h>
277836SJohn.Forte@Sun.COM #include <sys/file.h>
287836SJohn.Forte@Sun.COM #include <sys/ddi.h>
297836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
307836SJohn.Forte@Sun.COM #include <sys/modctl.h>
317836SJohn.Forte@Sun.COM #include <sys/scsi/scsi.h>
327836SJohn.Forte@Sun.COM #include <sys/scsi/impl/scsi_reset_notify.h>
337836SJohn.Forte@Sun.COM #include <sys/disp.h>
347836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
357836SJohn.Forte@Sun.COM #include <sys/atomic.h>
367836SJohn.Forte@Sun.COM #include <sys/ethernet.h>
377836SJohn.Forte@Sun.COM #include <sys/sdt.h>
387836SJohn.Forte@Sun.COM #include <sys/nvpair.h>
397836SJohn.Forte@Sun.COM 
407836SJohn.Forte@Sun.COM #include <stmf.h>
417836SJohn.Forte@Sun.COM #include <lpif.h>
427836SJohn.Forte@Sun.COM #include <portif.h>
437836SJohn.Forte@Sun.COM #include <stmf_ioctl.h>
447836SJohn.Forte@Sun.COM #include <stmf_impl.h>
457836SJohn.Forte@Sun.COM #include <lun_map.h>
467836SJohn.Forte@Sun.COM #include <stmf_state.h>
477836SJohn.Forte@Sun.COM 
487836SJohn.Forte@Sun.COM static uint64_t stmf_session_counter = 0;
497836SJohn.Forte@Sun.COM static uint16_t stmf_rtpid_counter = 0;
507836SJohn.Forte@Sun.COM 
517836SJohn.Forte@Sun.COM static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
527836SJohn.Forte@Sun.COM static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
537836SJohn.Forte@Sun.COM static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
547836SJohn.Forte@Sun.COM 	void **result);
557836SJohn.Forte@Sun.COM static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp);
567836SJohn.Forte@Sun.COM static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp);
577836SJohn.Forte@Sun.COM static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
587836SJohn.Forte@Sun.COM 	cred_t *credp, int *rval);
597836SJohn.Forte@Sun.COM static int stmf_get_stmf_state(stmf_state_desc_t *std);
607836SJohn.Forte@Sun.COM static int stmf_set_stmf_state(stmf_state_desc_t *std);
617836SJohn.Forte@Sun.COM static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu,
627836SJohn.Forte@Sun.COM     char *info);
637836SJohn.Forte@Sun.COM void stmf_svc_init();
647836SJohn.Forte@Sun.COM stmf_status_t stmf_svc_fini();
657836SJohn.Forte@Sun.COM void stmf_svc(void *arg);
667836SJohn.Forte@Sun.COM void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
677836SJohn.Forte@Sun.COM void stmf_check_freetask();
687836SJohn.Forte@Sun.COM void stmf_abort_target_reset(scsi_task_t *task);
697836SJohn.Forte@Sun.COM stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task,
707836SJohn.Forte@Sun.COM 							int target_reset);
717836SJohn.Forte@Sun.COM void stmf_target_reset_poll(struct scsi_task *task);
727836SJohn.Forte@Sun.COM void stmf_handle_lun_reset(scsi_task_t *task);
737836SJohn.Forte@Sun.COM void stmf_handle_target_reset(scsi_task_t *task);
747836SJohn.Forte@Sun.COM void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf);
757836SJohn.Forte@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi);
767836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
777836SJohn.Forte@Sun.COM void stmf_delete_ppd(stmf_pp_data_t *ppd);
787836SJohn.Forte@Sun.COM void stmf_delete_all_ppds();
797836SJohn.Forte@Sun.COM void stmf_trace_clear();
807836SJohn.Forte@Sun.COM void stmf_worker_init();
817836SJohn.Forte@Sun.COM stmf_status_t stmf_worker_fini();
827836SJohn.Forte@Sun.COM void stmf_worker_mgmt();
837836SJohn.Forte@Sun.COM void stmf_worker_task(void *arg);
847836SJohn.Forte@Sun.COM 
857836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops;
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM /* =====[ Tunables ]===== */
887836SJohn.Forte@Sun.COM /* Internal tracing */
897836SJohn.Forte@Sun.COM volatile int	stmf_trace_on = 1;
907836SJohn.Forte@Sun.COM volatile int	stmf_trace_buf_size = (1 * 1024 * 1024);
917836SJohn.Forte@Sun.COM /*
927836SJohn.Forte@Sun.COM  * The reason default task timeout is 75 is because we want the
937836SJohn.Forte@Sun.COM  * host to timeout 1st and mostly host timeout is 60 seconds.
947836SJohn.Forte@Sun.COM  */
957836SJohn.Forte@Sun.COM volatile int	stmf_default_task_timeout = 75;
967836SJohn.Forte@Sun.COM /*
977836SJohn.Forte@Sun.COM  * Setting this to one means, you are responsible for config load and keeping
987836SJohn.Forte@Sun.COM  * things in sync with persistent database.
997836SJohn.Forte@Sun.COM  */
1007836SJohn.Forte@Sun.COM volatile int	stmf_allow_modunload = 0;
1017836SJohn.Forte@Sun.COM 
1027836SJohn.Forte@Sun.COM volatile int stmf_max_nworkers = 256;
1037836SJohn.Forte@Sun.COM volatile int stmf_min_nworkers = 4;
1047836SJohn.Forte@Sun.COM volatile int stmf_worker_scale_down_delay = 20;
1057836SJohn.Forte@Sun.COM 
1067836SJohn.Forte@Sun.COM /* === [ Debugging and fault injection ] === */
1077836SJohn.Forte@Sun.COM #ifdef	DEBUG
1087836SJohn.Forte@Sun.COM volatile int stmf_drop_task_counter = 0;
1097836SJohn.Forte@Sun.COM volatile int stmf_drop_buf_counter = 0;
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM #endif
1127836SJohn.Forte@Sun.COM 
1137836SJohn.Forte@Sun.COM stmf_state_t		stmf_state;
1147836SJohn.Forte@Sun.COM static stmf_lu_t	*dlun0;
1157836SJohn.Forte@Sun.COM 
1167836SJohn.Forte@Sun.COM static uint8_t stmf_first_zero[] =
1177836SJohn.Forte@Sun.COM 	{ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
1187836SJohn.Forte@Sun.COM static uint8_t stmf_first_one[] =
1197836SJohn.Forte@Sun.COM 	{ 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM static kmutex_t	trace_buf_lock;
1227836SJohn.Forte@Sun.COM static int	trace_buf_size;
1237836SJohn.Forte@Sun.COM static int	trace_buf_curndx;
1247836SJohn.Forte@Sun.COM caddr_t	stmf_trace_buf;
1257836SJohn.Forte@Sun.COM 
1267836SJohn.Forte@Sun.COM static enum {
1277836SJohn.Forte@Sun.COM 	STMF_WORKERS_DISABLED = 0,
1287836SJohn.Forte@Sun.COM 	STMF_WORKERS_ENABLING,
1297836SJohn.Forte@Sun.COM 	STMF_WORKERS_ENABLED
1307836SJohn.Forte@Sun.COM } stmf_workers_state = STMF_WORKERS_DISABLED;
1317836SJohn.Forte@Sun.COM static int stmf_i_max_nworkers;
1327836SJohn.Forte@Sun.COM static int stmf_i_min_nworkers;
1337836SJohn.Forte@Sun.COM static int stmf_nworkers_cur;		/* # of workers currently running */
1347836SJohn.Forte@Sun.COM static int stmf_nworkers_needed;	/* # of workers need to be running */
1357836SJohn.Forte@Sun.COM static int stmf_worker_sel_counter = 0;
1367836SJohn.Forte@Sun.COM static uint32_t stmf_cur_ntasks = 0;
1377836SJohn.Forte@Sun.COM static clock_t stmf_wm_last = 0;
1387836SJohn.Forte@Sun.COM /*
1397836SJohn.Forte@Sun.COM  * This is equal to stmf_nworkers_cur while we are increasing # workers and
1407836SJohn.Forte@Sun.COM  * stmf_nworkers_needed while we are decreasing the worker count.
1417836SJohn.Forte@Sun.COM  */
1427836SJohn.Forte@Sun.COM static int stmf_nworkers_accepting_cmds;
1437836SJohn.Forte@Sun.COM static stmf_worker_t *stmf_workers = NULL;
1447836SJohn.Forte@Sun.COM static clock_t stmf_worker_mgmt_delay = 2;
1457836SJohn.Forte@Sun.COM static clock_t stmf_worker_scale_down_timer = 0;
1467836SJohn.Forte@Sun.COM static int stmf_worker_scale_down_qd = 0;
1477836SJohn.Forte@Sun.COM 
1487836SJohn.Forte@Sun.COM static struct cb_ops stmf_cb_ops = {
1497836SJohn.Forte@Sun.COM 	stmf_open,			/* open */
1507836SJohn.Forte@Sun.COM 	stmf_close,			/* close */
1517836SJohn.Forte@Sun.COM 	nodev,				/* strategy */
1527836SJohn.Forte@Sun.COM 	nodev,				/* print */
1537836SJohn.Forte@Sun.COM 	nodev,				/* dump */
1547836SJohn.Forte@Sun.COM 	nodev,				/* read */
1557836SJohn.Forte@Sun.COM 	nodev,				/* write */
1567836SJohn.Forte@Sun.COM 	stmf_ioctl,			/* ioctl */
1577836SJohn.Forte@Sun.COM 	nodev,				/* devmap */
1587836SJohn.Forte@Sun.COM 	nodev,				/* mmap */
1597836SJohn.Forte@Sun.COM 	nodev,				/* segmap */
1607836SJohn.Forte@Sun.COM 	nochpoll,			/* chpoll */
1617836SJohn.Forte@Sun.COM 	ddi_prop_op,			/* cb_prop_op */
1627836SJohn.Forte@Sun.COM 	0,				/* streamtab */
1637836SJohn.Forte@Sun.COM 	D_NEW | D_MP,			/* cb_flag */
1647836SJohn.Forte@Sun.COM 	CB_REV,				/* rev */
1657836SJohn.Forte@Sun.COM 	nodev,				/* aread */
1667836SJohn.Forte@Sun.COM 	nodev				/* awrite */
1677836SJohn.Forte@Sun.COM };
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM static struct dev_ops stmf_ops = {
1707836SJohn.Forte@Sun.COM 	DEVO_REV,
1717836SJohn.Forte@Sun.COM 	0,
1727836SJohn.Forte@Sun.COM 	stmf_getinfo,
1737836SJohn.Forte@Sun.COM 	nulldev,		/* identify */
1747836SJohn.Forte@Sun.COM 	nulldev,		/* probe */
1757836SJohn.Forte@Sun.COM 	stmf_attach,
1767836SJohn.Forte@Sun.COM 	stmf_detach,
1777836SJohn.Forte@Sun.COM 	nodev,			/* reset */
1787836SJohn.Forte@Sun.COM 	&stmf_cb_ops,
1797836SJohn.Forte@Sun.COM 	NULL,			/* bus_ops */
1807836SJohn.Forte@Sun.COM 	NULL			/* power */
1817836SJohn.Forte@Sun.COM };
1827836SJohn.Forte@Sun.COM 
1837836SJohn.Forte@Sun.COM #define	STMF_NAME	"COMSTAR STMF"
1847836SJohn.Forte@Sun.COM 
1857836SJohn.Forte@Sun.COM static struct modldrv modldrv = {
1867836SJohn.Forte@Sun.COM 	&mod_driverops,
1877836SJohn.Forte@Sun.COM 	STMF_NAME,
1887836SJohn.Forte@Sun.COM 	&stmf_ops
1897836SJohn.Forte@Sun.COM };
1907836SJohn.Forte@Sun.COM 
1917836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
1927836SJohn.Forte@Sun.COM 	MODREV_1,
1937836SJohn.Forte@Sun.COM 	&modldrv,
1947836SJohn.Forte@Sun.COM 	NULL
1957836SJohn.Forte@Sun.COM };
1967836SJohn.Forte@Sun.COM 
1977836SJohn.Forte@Sun.COM int
1987836SJohn.Forte@Sun.COM _init(void)
1997836SJohn.Forte@Sun.COM {
2007836SJohn.Forte@Sun.COM 	int ret;
2017836SJohn.Forte@Sun.COM 
2027836SJohn.Forte@Sun.COM 	ret = mod_install(&modlinkage);
2037836SJohn.Forte@Sun.COM 	if (ret)
2047836SJohn.Forte@Sun.COM 		return (ret);
2057836SJohn.Forte@Sun.COM 	stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP);
2067836SJohn.Forte@Sun.COM 	trace_buf_size = stmf_trace_buf_size;
2077836SJohn.Forte@Sun.COM 	trace_buf_curndx = 0;
2087836SJohn.Forte@Sun.COM 	mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0);
2097836SJohn.Forte@Sun.COM 	bzero(&stmf_state, sizeof (stmf_state_t));
2107836SJohn.Forte@Sun.COM 	/* STMF service is off by default */
2117836SJohn.Forte@Sun.COM 	stmf_state.stmf_service_running = 0;
2127836SJohn.Forte@Sun.COM 	mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL);
2137836SJohn.Forte@Sun.COM 	cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL);
2147836SJohn.Forte@Sun.COM 	stmf_session_counter = (uint64_t)ddi_get_lbolt();
2157836SJohn.Forte@Sun.COM 	stmf_view_init();
2167836SJohn.Forte@Sun.COM 	stmf_svc_init();
2177836SJohn.Forte@Sun.COM 	stmf_dlun_init();
2187836SJohn.Forte@Sun.COM 	return (ret);
2197836SJohn.Forte@Sun.COM }
2207836SJohn.Forte@Sun.COM 
2217836SJohn.Forte@Sun.COM int
2227836SJohn.Forte@Sun.COM _fini(void)
2237836SJohn.Forte@Sun.COM {
2247836SJohn.Forte@Sun.COM 	int ret;
2257836SJohn.Forte@Sun.COM 
2267836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running)
2277836SJohn.Forte@Sun.COM 		return (EBUSY);
2287836SJohn.Forte@Sun.COM 	if ((!stmf_allow_modunload) &&
2297836SJohn.Forte@Sun.COM 	    (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) {
2307836SJohn.Forte@Sun.COM 		return (EBUSY);
2317836SJohn.Forte@Sun.COM 	}
2327836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_nlps || stmf_state.stmf_npps) {
2337836SJohn.Forte@Sun.COM 		return (EBUSY);
2347836SJohn.Forte@Sun.COM 	}
2357836SJohn.Forte@Sun.COM 	if (stmf_dlun_fini() != STMF_SUCCESS)
2367836SJohn.Forte@Sun.COM 		return (EBUSY);
2377836SJohn.Forte@Sun.COM 	if (stmf_worker_fini() != STMF_SUCCESS) {
2387836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2397836SJohn.Forte@Sun.COM 		return (EBUSY);
2407836SJohn.Forte@Sun.COM 	}
2417836SJohn.Forte@Sun.COM 	if (stmf_svc_fini() != STMF_SUCCESS) {
2427836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2437836SJohn.Forte@Sun.COM 		stmf_worker_init();
2447836SJohn.Forte@Sun.COM 		return (EBUSY);
2457836SJohn.Forte@Sun.COM 	}
2467836SJohn.Forte@Sun.COM 
2477836SJohn.Forte@Sun.COM 	ret = mod_remove(&modlinkage);
2487836SJohn.Forte@Sun.COM 	if (ret) {
2497836SJohn.Forte@Sun.COM 		stmf_svc_init();
2507836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2517836SJohn.Forte@Sun.COM 		stmf_worker_init();
2527836SJohn.Forte@Sun.COM 		return (ret);
2537836SJohn.Forte@Sun.COM 	}
2547836SJohn.Forte@Sun.COM 
2557836SJohn.Forte@Sun.COM 	stmf_view_clear_config();
2567836SJohn.Forte@Sun.COM 	kmem_free(stmf_trace_buf, stmf_trace_buf_size);
2577836SJohn.Forte@Sun.COM 	mutex_destroy(&trace_buf_lock);
2587836SJohn.Forte@Sun.COM 	mutex_destroy(&stmf_state.stmf_lock);
2597836SJohn.Forte@Sun.COM 	cv_destroy(&stmf_state.stmf_cv);
2607836SJohn.Forte@Sun.COM 	return (ret);
2617836SJohn.Forte@Sun.COM }
2627836SJohn.Forte@Sun.COM 
2637836SJohn.Forte@Sun.COM int
2647836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
2657836SJohn.Forte@Sun.COM {
2667836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
2677836SJohn.Forte@Sun.COM }
2687836SJohn.Forte@Sun.COM 
2697836SJohn.Forte@Sun.COM /* ARGSUSED */
2707836SJohn.Forte@Sun.COM static int
2717836SJohn.Forte@Sun.COM stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2727836SJohn.Forte@Sun.COM {
2737836SJohn.Forte@Sun.COM 	switch (cmd) {
2747836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
2757836SJohn.Forte@Sun.COM 		*result = stmf_state.stmf_dip;
2767836SJohn.Forte@Sun.COM 		break;
2777836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
2787836SJohn.Forte@Sun.COM 		*result = (void *)(uintptr_t)ddi_get_instance(dip);
2797836SJohn.Forte@Sun.COM 		break;
2807836SJohn.Forte@Sun.COM 	default:
2817836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
2827836SJohn.Forte@Sun.COM 	}
2837836SJohn.Forte@Sun.COM 
2847836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
2857836SJohn.Forte@Sun.COM }
2867836SJohn.Forte@Sun.COM 
2877836SJohn.Forte@Sun.COM static int
2887836SJohn.Forte@Sun.COM stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2897836SJohn.Forte@Sun.COM {
2907836SJohn.Forte@Sun.COM 	switch (cmd) {
2917836SJohn.Forte@Sun.COM 	case DDI_ATTACH:
2927836SJohn.Forte@Sun.COM 		stmf_state.stmf_dip = dip;
2937836SJohn.Forte@Sun.COM 
2947836SJohn.Forte@Sun.COM 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
2957836SJohn.Forte@Sun.COM 		    DDI_NT_STMF, 0) != DDI_SUCCESS) {
2967836SJohn.Forte@Sun.COM 			break;
2977836SJohn.Forte@Sun.COM 		}
2987836SJohn.Forte@Sun.COM 		ddi_report_dev(dip);
2997836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
3007836SJohn.Forte@Sun.COM 	}
3017836SJohn.Forte@Sun.COM 
3027836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
3037836SJohn.Forte@Sun.COM }
3047836SJohn.Forte@Sun.COM 
3057836SJohn.Forte@Sun.COM static int
3067836SJohn.Forte@Sun.COM stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3077836SJohn.Forte@Sun.COM {
3087836SJohn.Forte@Sun.COM 	switch (cmd) {
3097836SJohn.Forte@Sun.COM 	case DDI_DETACH:
3107836SJohn.Forte@Sun.COM 		ddi_remove_minor_node(dip, 0);
3117836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
3127836SJohn.Forte@Sun.COM 	}
3137836SJohn.Forte@Sun.COM 
3147836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
3157836SJohn.Forte@Sun.COM }
3167836SJohn.Forte@Sun.COM 
3177836SJohn.Forte@Sun.COM /* ARGSUSED */
3187836SJohn.Forte@Sun.COM static int
3197836SJohn.Forte@Sun.COM stmf_open(dev_t *devp, int flag, int otype, cred_t *credp)
3207836SJohn.Forte@Sun.COM {
3217836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
3227836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_exclusive_open) {
3237836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
3247836SJohn.Forte@Sun.COM 		return (EBUSY);
3257836SJohn.Forte@Sun.COM 	}
3267836SJohn.Forte@Sun.COM 	if (flag & FEXCL) {
3277836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_opened) {
3287836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
3297836SJohn.Forte@Sun.COM 			return (EBUSY);
3307836SJohn.Forte@Sun.COM 		}
3317836SJohn.Forte@Sun.COM 		stmf_state.stmf_exclusive_open = 1;
3327836SJohn.Forte@Sun.COM 	}
3337836SJohn.Forte@Sun.COM 	stmf_state.stmf_opened = 1;
3347836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
3357836SJohn.Forte@Sun.COM 	return (0);
3367836SJohn.Forte@Sun.COM }
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM /* ARGSUSED */
3397836SJohn.Forte@Sun.COM static int
3407836SJohn.Forte@Sun.COM stmf_close(dev_t dev, int flag, int otype, cred_t *credp)
3417836SJohn.Forte@Sun.COM {
3427836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
3437836SJohn.Forte@Sun.COM 	stmf_state.stmf_opened = 0;
3447836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_exclusive_open &&
3457836SJohn.Forte@Sun.COM 	    (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) {
3467836SJohn.Forte@Sun.COM 		stmf_state.stmf_config_state = STMF_CONFIG_NONE;
3477836SJohn.Forte@Sun.COM 		stmf_delete_all_ppds();
3487836SJohn.Forte@Sun.COM 		stmf_view_clear_config();
3497836SJohn.Forte@Sun.COM 		stmf_view_init();
3507836SJohn.Forte@Sun.COM 	}
3517836SJohn.Forte@Sun.COM 	stmf_state.stmf_exclusive_open = 0;
3527836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
3537836SJohn.Forte@Sun.COM 	return (0);
3547836SJohn.Forte@Sun.COM }
3557836SJohn.Forte@Sun.COM 
3567836SJohn.Forte@Sun.COM int
3577836SJohn.Forte@Sun.COM stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd,
3587836SJohn.Forte@Sun.COM 						void **ibuf, void **obuf)
3597836SJohn.Forte@Sun.COM {
3607836SJohn.Forte@Sun.COM 	int ret;
3617836SJohn.Forte@Sun.COM 
3627836SJohn.Forte@Sun.COM 	*ibuf = NULL;
3637836SJohn.Forte@Sun.COM 	*obuf = NULL;
3647836SJohn.Forte@Sun.COM 	*iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP);
3657836SJohn.Forte@Sun.COM 
3667836SJohn.Forte@Sun.COM 	ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode);
3677836SJohn.Forte@Sun.COM 	if (ret)
3687836SJohn.Forte@Sun.COM 		return (EFAULT);
3697836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_version != STMF_VERSION_1) {
3707836SJohn.Forte@Sun.COM 		ret = EINVAL;
3717836SJohn.Forte@Sun.COM 		goto copyin_iocdata_done;
3727836SJohn.Forte@Sun.COM 	}
3737836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_ibuf_size) {
3747836SJohn.Forte@Sun.COM 		*ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP);
3757836SJohn.Forte@Sun.COM 		ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf),
3767836SJohn.Forte@Sun.COM 		    *ibuf, (*iocd)->stmf_ibuf_size, mode);
3777836SJohn.Forte@Sun.COM 	}
3787836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_obuf_size)
3797836SJohn.Forte@Sun.COM 		*obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP);
3807836SJohn.Forte@Sun.COM 
3817836SJohn.Forte@Sun.COM 	if (ret == 0)
3827836SJohn.Forte@Sun.COM 		return (0);
3837836SJohn.Forte@Sun.COM 	ret = EFAULT;
3847836SJohn.Forte@Sun.COM copyin_iocdata_done:;
3857836SJohn.Forte@Sun.COM 	if (*obuf) {
3867836SJohn.Forte@Sun.COM 		kmem_free(*obuf, (*iocd)->stmf_obuf_size);
3877836SJohn.Forte@Sun.COM 		*obuf = NULL;
3887836SJohn.Forte@Sun.COM 	}
3897836SJohn.Forte@Sun.COM 	if (*ibuf) {
3907836SJohn.Forte@Sun.COM 		kmem_free(*ibuf, (*iocd)->stmf_ibuf_size);
3917836SJohn.Forte@Sun.COM 		*ibuf = NULL;
3927836SJohn.Forte@Sun.COM 	}
3937836SJohn.Forte@Sun.COM 	kmem_free(*iocd, sizeof (stmf_iocdata_t));
3947836SJohn.Forte@Sun.COM 	return (ret);
3957836SJohn.Forte@Sun.COM }
3967836SJohn.Forte@Sun.COM 
3977836SJohn.Forte@Sun.COM int
3987836SJohn.Forte@Sun.COM stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf)
3997836SJohn.Forte@Sun.COM {
4007836SJohn.Forte@Sun.COM 	int ret;
4017836SJohn.Forte@Sun.COM 
4027836SJohn.Forte@Sun.COM 	if (iocd->stmf_obuf_size) {
4037836SJohn.Forte@Sun.COM 		ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf,
4047836SJohn.Forte@Sun.COM 		    iocd->stmf_obuf_size, mode);
4057836SJohn.Forte@Sun.COM 		if (ret)
4067836SJohn.Forte@Sun.COM 			return (EFAULT);
4077836SJohn.Forte@Sun.COM 	}
4087836SJohn.Forte@Sun.COM 	ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode);
4097836SJohn.Forte@Sun.COM 	if (ret)
4107836SJohn.Forte@Sun.COM 		return (EFAULT);
4117836SJohn.Forte@Sun.COM 	return (0);
4127836SJohn.Forte@Sun.COM }
4137836SJohn.Forte@Sun.COM 
4147836SJohn.Forte@Sun.COM /* ARGSUSED */
4157836SJohn.Forte@Sun.COM static int
4167836SJohn.Forte@Sun.COM stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
4177836SJohn.Forte@Sun.COM 	cred_t *credp, int *rval)
4187836SJohn.Forte@Sun.COM {
4197836SJohn.Forte@Sun.COM 	stmf_iocdata_t *iocd;
4207836SJohn.Forte@Sun.COM 	void *ibuf = NULL, *obuf = NULL;
4217836SJohn.Forte@Sun.COM 	slist_lu_t *luid_list;
4227836SJohn.Forte@Sun.COM 	slist_target_port_t *lportid_list;
4237836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
4247836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
4257836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
4267836SJohn.Forte@Sun.COM 	slist_scsi_session_t *iss_list;
4277836SJohn.Forte@Sun.COM 	sioc_lu_props_t *lup;
4287836SJohn.Forte@Sun.COM 	sioc_target_port_props_t *lportp;
4297836SJohn.Forte@Sun.COM 	stmf_ppioctl_data_t *ppi;
4307836SJohn.Forte@Sun.COM 	uint8_t *p_id;
4317836SJohn.Forte@Sun.COM 	stmf_state_desc_t *std;
4327836SJohn.Forte@Sun.COM 	stmf_status_t ctl_ret;
4337836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssi;
4347836SJohn.Forte@Sun.COM 	int ret = 0;
4357836SJohn.Forte@Sun.COM 	uint32_t n;
4367836SJohn.Forte@Sun.COM 	int i;
4377836SJohn.Forte@Sun.COM 	stmf_group_op_data_t *grp_entry;
4387836SJohn.Forte@Sun.COM 	stmf_group_name_t *grpname;
4397836SJohn.Forte@Sun.COM 	stmf_view_op_entry_t *ve;
4407836SJohn.Forte@Sun.COM 	stmf_id_type_t idtype;
4417836SJohn.Forte@Sun.COM #if 0
4427836SJohn.Forte@Sun.COM 	stmf_id_data_t *id_entry;
4437836SJohn.Forte@Sun.COM 	stmf_id_list_t	*id_list;
4447836SJohn.Forte@Sun.COM 	stmf_view_entry_t *view_entry;
4457836SJohn.Forte@Sun.COM #endif
4467836SJohn.Forte@Sun.COM 	uint32_t	veid;
4477836SJohn.Forte@Sun.COM 
4487836SJohn.Forte@Sun.COM 	if ((cmd & 0xff000000) != STMF_IOCTL) {
4497836SJohn.Forte@Sun.COM 		return (ENOTTY);
4507836SJohn.Forte@Sun.COM 	}
4517836SJohn.Forte@Sun.COM 
4527836SJohn.Forte@Sun.COM 	if (drv_priv(credp) != 0) {
4537836SJohn.Forte@Sun.COM 		return (EPERM);
4547836SJohn.Forte@Sun.COM 	}
4557836SJohn.Forte@Sun.COM 
4567836SJohn.Forte@Sun.COM 	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
4577836SJohn.Forte@Sun.COM 	if (ret)
4587836SJohn.Forte@Sun.COM 		return (ret);
4597836SJohn.Forte@Sun.COM 	iocd->stmf_error = 0;
4607836SJohn.Forte@Sun.COM 
4617836SJohn.Forte@Sun.COM 	switch (cmd) {
4627836SJohn.Forte@Sun.COM 	case STMF_IOCTL_LU_LIST:
4637836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
4647836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus;
4657836SJohn.Forte@Sun.COM 		n = min(stmf_state.stmf_nlus,
4667836SJohn.Forte@Sun.COM 				(iocd->stmf_obuf_size)/sizeof (slist_lu_t));
4677836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
4687836SJohn.Forte@Sun.COM 		ilu = stmf_state.stmf_ilulist;
4697836SJohn.Forte@Sun.COM 		luid_list = (slist_lu_t *)obuf;
4707836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
4717836SJohn.Forte@Sun.COM 			uint8_t *id;
4727836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilu->ilu_lu->lu_id;
4737836SJohn.Forte@Sun.COM 			bcopy(id + 4, luid_list[i].lu_guid, 16);
4747836SJohn.Forte@Sun.COM 			ilu = ilu->ilu_next;
4757836SJohn.Forte@Sun.COM 		}
4767836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
4777836SJohn.Forte@Sun.COM 		break;
4787836SJohn.Forte@Sun.COM 
4797836SJohn.Forte@Sun.COM 	case STMF_IOCTL_TARGET_PORT_LIST:
4807836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
4817836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports;
4827836SJohn.Forte@Sun.COM 		n = min(stmf_state.stmf_nlports,
4837836SJohn.Forte@Sun.COM 			(iocd->stmf_obuf_size)/sizeof (slist_target_port_t));
4847836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
4857836SJohn.Forte@Sun.COM 		ilport = stmf_state.stmf_ilportlist;
4867836SJohn.Forte@Sun.COM 		lportid_list = (slist_target_port_t *)obuf;
4877836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
4887836SJohn.Forte@Sun.COM 			uint8_t *id;
4897836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
4907836SJohn.Forte@Sun.COM 			bcopy(id, lportid_list[i].target, id[3] + 4);
4917836SJohn.Forte@Sun.COM 			ilport = ilport->ilport_next;
4927836SJohn.Forte@Sun.COM 		}
4937836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
4947836SJohn.Forte@Sun.COM 		break;
4957836SJohn.Forte@Sun.COM 
4967836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SESSION_LIST:
4977836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
4987836SJohn.Forte@Sun.COM 		if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) ||
4997836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < (p_id[3] + 4))) {
5007836SJohn.Forte@Sun.COM 			ret = EINVAL;
5017836SJohn.Forte@Sun.COM 			break;
5027836SJohn.Forte@Sun.COM 		}
5037836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5047836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport; ilport =
5057836SJohn.Forte@Sun.COM 				ilport->ilport_next) {
5067836SJohn.Forte@Sun.COM 			uint8_t *id;
5077836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
5087836SJohn.Forte@Sun.COM 			if ((p_id[3] == id[3]) &&
5097836SJohn.Forte@Sun.COM 			    (bcmp(p_id + 4, id + 4, id[3]) == 0)) {
5107836SJohn.Forte@Sun.COM 				break;
5117836SJohn.Forte@Sun.COM 			}
5127836SJohn.Forte@Sun.COM 		}
5137836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
5147836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
5157836SJohn.Forte@Sun.COM 			ret = ENOENT;
5167836SJohn.Forte@Sun.COM 			break;
5177836SJohn.Forte@Sun.COM 		}
5187836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions;
5197836SJohn.Forte@Sun.COM 		n = min(ilport->ilport_nsessions,
5207836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t));
5217836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
5227836SJohn.Forte@Sun.COM 		iss = ilport->ilport_ss_list;
5237836SJohn.Forte@Sun.COM 		iss_list = (slist_scsi_session_t *)obuf;
5247836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
5257836SJohn.Forte@Sun.COM 			uint8_t *id;
5267836SJohn.Forte@Sun.COM 			id = (uint8_t *)iss->iss_ss->ss_rport_id;
5277836SJohn.Forte@Sun.COM 			bcopy(id, iss_list[i].initiator, id[3] + 4);
5287836SJohn.Forte@Sun.COM 			iss_list[i].creation_time = (uint32_t)
5297836SJohn.Forte@Sun.COM 			    iss->iss_creation_time;
5307836SJohn.Forte@Sun.COM 			if (iss->iss_ss->ss_rport_alias) {
5317836SJohn.Forte@Sun.COM 				(void) strncpy(iss_list[i].alias,
5327836SJohn.Forte@Sun.COM 				    iss->iss_ss->ss_rport_alias, 255);
5337836SJohn.Forte@Sun.COM 				iss_list[i].alias[255] = 0;
5347836SJohn.Forte@Sun.COM 			} else {
5357836SJohn.Forte@Sun.COM 				iss_list[i].alias[0] = 0;
5367836SJohn.Forte@Sun.COM 			}
5377836SJohn.Forte@Sun.COM 			iss = iss->iss_next;
5387836SJohn.Forte@Sun.COM 		}
5397836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5407836SJohn.Forte@Sun.COM 		break;
5417836SJohn.Forte@Sun.COM 
5427836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_LU_PROPERTIES:
5437836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
5447836SJohn.Forte@Sun.COM 		if ((iocd->stmf_ibuf_size < 16) ||
5457836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) ||
5467836SJohn.Forte@Sun.COM 		    (p_id[0] == 0)) {
5477836SJohn.Forte@Sun.COM 			ret = EINVAL;
5487836SJohn.Forte@Sun.COM 			break;
5497836SJohn.Forte@Sun.COM 		}
5507836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5517836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
5527836SJohn.Forte@Sun.COM 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
5537836SJohn.Forte@Sun.COM 				break;
5547836SJohn.Forte@Sun.COM 		}
5557836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
5567836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
5577836SJohn.Forte@Sun.COM 			ret = ENOENT;
5587836SJohn.Forte@Sun.COM 			break;
5597836SJohn.Forte@Sun.COM 		}
5607836SJohn.Forte@Sun.COM 		lup = (sioc_lu_props_t *)obuf;
5617836SJohn.Forte@Sun.COM 		bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16);
5627836SJohn.Forte@Sun.COM 		lup->lu_state = ilu->ilu_state & 0x0f;
5637836SJohn.Forte@Sun.COM 		lup->lu_present = 1; /* XXX */
5647836SJohn.Forte@Sun.COM 		(void) strncpy(lup->lu_provider_name,
5657836SJohn.Forte@Sun.COM 		    ilu->ilu_lu->lu_lp->lp_name, 255);
5667836SJohn.Forte@Sun.COM 		lup->lu_provider_name[254] = 0;
5677836SJohn.Forte@Sun.COM 		if (ilu->ilu_lu->lu_alias) {
5687836SJohn.Forte@Sun.COM 			(void) strncpy(lup->lu_alias,
5697836SJohn.Forte@Sun.COM 			    ilu->ilu_lu->lu_alias, 255);
5707836SJohn.Forte@Sun.COM 			lup->lu_alias[255] = 0;
5717836SJohn.Forte@Sun.COM 		} else {
5727836SJohn.Forte@Sun.COM 			lup->lu_alias[0] = 0;
5737836SJohn.Forte@Sun.COM 		}
5747836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5757836SJohn.Forte@Sun.COM 		break;
5767836SJohn.Forte@Sun.COM 
5777836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES:
5787836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
5797836SJohn.Forte@Sun.COM 		if ((p_id == NULL) ||
5807836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < (p_id[3] + 4)) ||
5817836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size <
5827836SJohn.Forte@Sun.COM 		    sizeof (sioc_target_port_props_t))) {
5837836SJohn.Forte@Sun.COM 			ret = EINVAL;
5847836SJohn.Forte@Sun.COM 			break;
5857836SJohn.Forte@Sun.COM 		}
5867836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5877836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport;
5887836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
5897836SJohn.Forte@Sun.COM 			uint8_t *id;
5907836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
5917836SJohn.Forte@Sun.COM 			if ((p_id[3] == id[3]) &&
5927836SJohn.Forte@Sun.COM 			    (bcmp(p_id+4, id+4, id[3]) == 0))
5937836SJohn.Forte@Sun.COM 				break;
5947836SJohn.Forte@Sun.COM 		}
5957836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
5967836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
5977836SJohn.Forte@Sun.COM 			ret = ENOENT;
5987836SJohn.Forte@Sun.COM 			break;
5997836SJohn.Forte@Sun.COM 		}
6007836SJohn.Forte@Sun.COM 		lportp = (sioc_target_port_props_t *)obuf;
6017836SJohn.Forte@Sun.COM 		bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id,
6027836SJohn.Forte@Sun.COM 		    ilport->ilport_lport->lport_id->ident_length + 4);
6037836SJohn.Forte@Sun.COM 		lportp->tgt_state = ilport->ilport_state & 0x0f;
6047836SJohn.Forte@Sun.COM 		lportp->tgt_present = 1; /* XXX */
6057836SJohn.Forte@Sun.COM 		(void) strncpy(lportp->tgt_provider_name,
6067836SJohn.Forte@Sun.COM 		    ilport->ilport_lport->lport_pp->pp_name, 255);
6077836SJohn.Forte@Sun.COM 		lportp->tgt_provider_name[254] = 0;
6087836SJohn.Forte@Sun.COM 		if (ilport->ilport_lport->lport_alias) {
6097836SJohn.Forte@Sun.COM 			(void) strncpy(lportp->tgt_alias,
6107836SJohn.Forte@Sun.COM 			    ilport->ilport_lport->lport_alias, 255);
6117836SJohn.Forte@Sun.COM 			lportp->tgt_alias[255] = 0;
6127836SJohn.Forte@Sun.COM 		} else {
6137836SJohn.Forte@Sun.COM 			lportp->tgt_alias[0] = 0;
6147836SJohn.Forte@Sun.COM 		}
6157836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
6167836SJohn.Forte@Sun.COM 		break;
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_STMF_STATE:
6197836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
6207836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
6217836SJohn.Forte@Sun.COM 			ret = EINVAL;
6227836SJohn.Forte@Sun.COM 			break;
6237836SJohn.Forte@Sun.COM 		}
6247836SJohn.Forte@Sun.COM 		ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf);
6257836SJohn.Forte@Sun.COM 		break;
6267836SJohn.Forte@Sun.COM 
6277836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_STMF_STATE:
6287836SJohn.Forte@Sun.COM 		if ((obuf == NULL) ||
6297836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) {
6307836SJohn.Forte@Sun.COM 			ret = EINVAL;
6317836SJohn.Forte@Sun.COM 			break;
6327836SJohn.Forte@Sun.COM 		}
6337836SJohn.Forte@Sun.COM 		ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf);
6347836SJohn.Forte@Sun.COM 		break;
6357836SJohn.Forte@Sun.COM 
6367836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_LU_STATE:
6377836SJohn.Forte@Sun.COM 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
6387836SJohn.Forte@Sun.COM 		ssi.st_additional_info = NULL;
6397836SJohn.Forte@Sun.COM 		std = (stmf_state_desc_t *)ibuf;
6407836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
6417836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
6427836SJohn.Forte@Sun.COM 			ret = EINVAL;
6437836SJohn.Forte@Sun.COM 			break;
6447836SJohn.Forte@Sun.COM 		}
6457836SJohn.Forte@Sun.COM 		p_id = std->ident;
6467836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
6477836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_inventory_locked) {
6487836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
6497836SJohn.Forte@Sun.COM 			ret = EBUSY;
6507836SJohn.Forte@Sun.COM 			break;
6517836SJohn.Forte@Sun.COM 		}
6527836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
6537836SJohn.Forte@Sun.COM 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
6547836SJohn.Forte@Sun.COM 				break;
6557836SJohn.Forte@Sun.COM 		}
6567836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
6577836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
6587836SJohn.Forte@Sun.COM 			ret = ENOENT;
6597836SJohn.Forte@Sun.COM 			break;
6607836SJohn.Forte@Sun.COM 		}
6617836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
6627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
6637836SJohn.Forte@Sun.COM 		cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE :
6647836SJohn.Forte@Sun.COM 		    STMF_CMD_LU_OFFLINE;
6657836SJohn.Forte@Sun.COM 		ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi);
6667836SJohn.Forte@Sun.COM 		if (ctl_ret == STMF_ALREADY)
6677836SJohn.Forte@Sun.COM 			ret = 0;
6687836SJohn.Forte@Sun.COM 		else if (ctl_ret != STMF_SUCCESS)
6697836SJohn.Forte@Sun.COM 			ret = EIO;
6707836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
6717836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
6727836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
6737836SJohn.Forte@Sun.COM 		break;
6747836SJohn.Forte@Sun.COM 
6757836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_TARGET_PORT_STATE:
6767836SJohn.Forte@Sun.COM 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
6777836SJohn.Forte@Sun.COM 		ssi.st_additional_info = NULL;
6787836SJohn.Forte@Sun.COM 		std = (stmf_state_desc_t *)ibuf;
6797836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
6807836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
6817836SJohn.Forte@Sun.COM 			ret = EINVAL;
6827836SJohn.Forte@Sun.COM 			break;
6837836SJohn.Forte@Sun.COM 		}
6847836SJohn.Forte@Sun.COM 		p_id = std->ident;
6857836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
6867836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_inventory_locked) {
6877836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
6887836SJohn.Forte@Sun.COM 			ret = EBUSY;
6897836SJohn.Forte@Sun.COM 			break;
6907836SJohn.Forte@Sun.COM 		}
6917836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport;
6927836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
6937836SJohn.Forte@Sun.COM 			uint8_t *id;
6947836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
6957836SJohn.Forte@Sun.COM 			if ((id[3] == p_id[3]) &&
6967836SJohn.Forte@Sun.COM 			    (bcmp(id+4, p_id+4, id[3]) == 0)) {
6977836SJohn.Forte@Sun.COM 				break;
6987836SJohn.Forte@Sun.COM 			}
6997836SJohn.Forte@Sun.COM 		}
7007836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
7017836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7027836SJohn.Forte@Sun.COM 			ret = ENOENT;
7037836SJohn.Forte@Sun.COM 			break;
7047836SJohn.Forte@Sun.COM 		}
7057836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
7067836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7077836SJohn.Forte@Sun.COM 		cmd = (std->state == STMF_STATE_ONLINE) ?
7087836SJohn.Forte@Sun.COM 		    STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE;
7097836SJohn.Forte@Sun.COM 		ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi);
7107836SJohn.Forte@Sun.COM 		if (ctl_ret == STMF_ALREADY)
7117836SJohn.Forte@Sun.COM 			ret = 0;
7127836SJohn.Forte@Sun.COM 		else if (ctl_ret != STMF_SUCCESS)
7137836SJohn.Forte@Sun.COM 			ret = EIO;
7147836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7157836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
7167836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7177836SJohn.Forte@Sun.COM 		break;
7187836SJohn.Forte@Sun.COM 
7197836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_HG_ENTRY:
7207836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST;
7217836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
7227836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_TG_ENTRY:
7237836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
7247836SJohn.Forte@Sun.COM 			ret = EACCES;
7257836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
7267836SJohn.Forte@Sun.COM 			break;
7277836SJohn.Forte@Sun.COM 		}
7287836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_ADD_TG_ENTRY) {
7297836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET;
7307836SJohn.Forte@Sun.COM 		}
7317836SJohn.Forte@Sun.COM 		grp_entry = (stmf_group_op_data_t *)ibuf;
7327836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
7337836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
7347836SJohn.Forte@Sun.COM 			ret = EINVAL;
7357836SJohn.Forte@Sun.COM 			break;
7367836SJohn.Forte@Sun.COM 		}
7377836SJohn.Forte@Sun.COM 		if (grp_entry->group.name[0] == '*') {
7387836SJohn.Forte@Sun.COM 			ret = EINVAL;
7397836SJohn.Forte@Sun.COM 			break; /* not allowed */
7407836SJohn.Forte@Sun.COM 		}
7417836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7427836SJohn.Forte@Sun.COM 		if (idtype == STMF_ID_TYPE_TARGET &&
7437836SJohn.Forte@Sun.COM 		    stmf_state.stmf_service_running) {
7447836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7457836SJohn.Forte@Sun.COM 			iocd->stmf_error =
7467836SJohn.Forte@Sun.COM 			    STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE;
7477836SJohn.Forte@Sun.COM 			ret = EBUSY;
7487836SJohn.Forte@Sun.COM 			break; /* not allowed */
7497836SJohn.Forte@Sun.COM 		}
7507836SJohn.Forte@Sun.COM 		ret = stmf_add_group_member(grp_entry->group.name,
7517836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
7527836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
7537836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
7547836SJohn.Forte@Sun.COM 		    idtype,
7557836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
7567836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7577836SJohn.Forte@Sun.COM 		break;
7587836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HG_ENTRY:
7597836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST;
7607836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
7617836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TG_ENTRY:
7627836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
7637836SJohn.Forte@Sun.COM 			ret = EACCES;
7647836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
7657836SJohn.Forte@Sun.COM 			break;
7667836SJohn.Forte@Sun.COM 		}
7677836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) {
7687836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET;
7697836SJohn.Forte@Sun.COM 		}
7707836SJohn.Forte@Sun.COM 		grp_entry = (stmf_group_op_data_t *)ibuf;
7717836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
7727836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
7737836SJohn.Forte@Sun.COM 			ret = EINVAL;
7747836SJohn.Forte@Sun.COM 			break;
7757836SJohn.Forte@Sun.COM 		}
7767836SJohn.Forte@Sun.COM 		if (grp_entry->group.name[0] == '*') {
7777836SJohn.Forte@Sun.COM 			ret = EINVAL;
7787836SJohn.Forte@Sun.COM 			break; /* not allowed */
7797836SJohn.Forte@Sun.COM 		}
7807836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7817836SJohn.Forte@Sun.COM 		if (idtype == STMF_ID_TYPE_TARGET &&
7827836SJohn.Forte@Sun.COM 		    stmf_state.stmf_service_running) {
7837836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7847836SJohn.Forte@Sun.COM 			iocd->stmf_error =
7857836SJohn.Forte@Sun.COM 			    STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE;
7867836SJohn.Forte@Sun.COM 			ret = EBUSY;
7877836SJohn.Forte@Sun.COM 			break; /* not allowed */
7887836SJohn.Forte@Sun.COM 		}
7897836SJohn.Forte@Sun.COM 		ret = stmf_remove_group_member(grp_entry->group.name,
7907836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
7917836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
7927836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
7937836SJohn.Forte@Sun.COM 		    idtype,
7947836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
7957836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7967836SJohn.Forte@Sun.COM 		break;
7977836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_HOST_GROUP:
7987836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
7997836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8007836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_TARGET_GROUP:
8017836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8027836SJohn.Forte@Sun.COM 			ret = EACCES;
8037836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8047836SJohn.Forte@Sun.COM 			break;
8057836SJohn.Forte@Sun.COM 		}
8067836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8077836SJohn.Forte@Sun.COM 
8087836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP)
8097836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8107836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8117836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8127836SJohn.Forte@Sun.COM 			ret = EINVAL;
8137836SJohn.Forte@Sun.COM 			break;
8147836SJohn.Forte@Sun.COM 		}
8157836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8167836SJohn.Forte@Sun.COM 			ret = EINVAL;
8177836SJohn.Forte@Sun.COM 			break; /* not allowed */
8187836SJohn.Forte@Sun.COM 		}
8197836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8207836SJohn.Forte@Sun.COM 		ret = stmf_add_group(grpname->name,
8217836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
8227836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8237836SJohn.Forte@Sun.COM 		break;
8247836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HOST_GROUP:
8257836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
8267836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8277836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TARGET_GROUP:
8287836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8297836SJohn.Forte@Sun.COM 			ret = EACCES;
8307836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8317836SJohn.Forte@Sun.COM 			break;
8327836SJohn.Forte@Sun.COM 		}
8337836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8347836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP)
8357836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8367836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8377836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8387836SJohn.Forte@Sun.COM 			ret = EINVAL;
8397836SJohn.Forte@Sun.COM 			break;
8407836SJohn.Forte@Sun.COM 		}
8417836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8427836SJohn.Forte@Sun.COM 			ret = EINVAL;
8437836SJohn.Forte@Sun.COM 			break; /* not allowed */
8447836SJohn.Forte@Sun.COM 		}
8457836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8467836SJohn.Forte@Sun.COM 		ret = stmf_remove_group(grpname->name,
8477836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
8487836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8497836SJohn.Forte@Sun.COM 		break;
8507836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_VIEW_ENTRY:
8517836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8527836SJohn.Forte@Sun.COM 			ret = EACCES;
8537836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8547836SJohn.Forte@Sun.COM 			break;
8557836SJohn.Forte@Sun.COM 		}
8567836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
8577836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8587836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
8597836SJohn.Forte@Sun.COM 			ret = EINVAL;
8607836SJohn.Forte@Sun.COM 			break;
8617836SJohn.Forte@Sun.COM 		}
8627836SJohn.Forte@Sun.COM 		if (!ve->ve_lu_number_valid)
8637836SJohn.Forte@Sun.COM 			ve->ve_lu_nbr[2] = 0xFF;
8647836SJohn.Forte@Sun.COM 		if (ve->ve_all_hosts) {
8657836SJohn.Forte@Sun.COM 			ve->ve_host_group.name[0] = '*';
8667836SJohn.Forte@Sun.COM 			ve->ve_host_group.name_size = 1;
8677836SJohn.Forte@Sun.COM 		}
8687836SJohn.Forte@Sun.COM 		if (ve->ve_all_targets) {
8697836SJohn.Forte@Sun.COM 			ve->ve_target_group.name[0] = '*';
8707836SJohn.Forte@Sun.COM 			ve->ve_target_group.name_size = 1;
8717836SJohn.Forte@Sun.COM 		}
8727836SJohn.Forte@Sun.COM 		if (ve->ve_ndx_valid)
8737836SJohn.Forte@Sun.COM 			veid = ve->ve_ndx;
8747836SJohn.Forte@Sun.COM 		else
8757836SJohn.Forte@Sun.COM 			veid = 0xffffffff;
8767836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8777836SJohn.Forte@Sun.COM 		ret = stmf_add_ve(ve->ve_host_group.name,
8787836SJohn.Forte@Sun.COM 		    ve->ve_host_group.name_size,
8797836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name,
8807836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name_size,
8817836SJohn.Forte@Sun.COM 		    ve->ve_guid,
8827836SJohn.Forte@Sun.COM 		    &veid,
8837836SJohn.Forte@Sun.COM 		    ve->ve_lu_nbr,
8847836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
8857836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8867836SJohn.Forte@Sun.COM 		if (ret == 0 &&
8877836SJohn.Forte@Sun.COM 		    (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) &&
8887836SJohn.Forte@Sun.COM 		    iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) {
8897836SJohn.Forte@Sun.COM 			stmf_view_op_entry_t *ve_ret =
8907836SJohn.Forte@Sun.COM 			    (stmf_view_op_entry_t *)obuf;
8917836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = 1;
8927836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = 1;
8937836SJohn.Forte@Sun.COM 			if (!ve->ve_ndx_valid) {
8947836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx = veid;
8957836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx_valid = 1;
8967836SJohn.Forte@Sun.COM 			}
8977836SJohn.Forte@Sun.COM 			if (!ve->ve_lu_number_valid) {
8987836SJohn.Forte@Sun.COM 				ve_ret->ve_lu_number_valid = 1;
8997836SJohn.Forte@Sun.COM 				bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8);
9007836SJohn.Forte@Sun.COM 			}
9017836SJohn.Forte@Sun.COM 		}
9027836SJohn.Forte@Sun.COM 		break;
9037836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_VIEW_ENTRY:
9047836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
9057836SJohn.Forte@Sun.COM 			ret = EACCES;
9067836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
9077836SJohn.Forte@Sun.COM 			break;
9087836SJohn.Forte@Sun.COM 		}
9097836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
9107836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9117836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
9127836SJohn.Forte@Sun.COM 			ret = EINVAL;
9137836SJohn.Forte@Sun.COM 			break;
9147836SJohn.Forte@Sun.COM 		}
9157836SJohn.Forte@Sun.COM 		if (!ve->ve_ndx_valid) {
9167836SJohn.Forte@Sun.COM 			ret = EINVAL;
9177836SJohn.Forte@Sun.COM 			break;
9187836SJohn.Forte@Sun.COM 		}
9197836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9207836SJohn.Forte@Sun.COM 		ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx,
9217836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
9227836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9237836SJohn.Forte@Sun.COM 		break;
9247836SJohn.Forte@Sun.COM #if 0
9257836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_LIST:
9267836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
9277836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
9287836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_LIST:
9297836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_LIST)
9307836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
9317836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9327836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
9337836SJohn.Forte@Sun.COM 		n = min(id_list->id_count,
9347836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t));
9357836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
9367836SJohn.Forte@Sun.COM 		id_entry = id_list->idl_head;
9377836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)obuf;
9387836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
9397836SJohn.Forte@Sun.COM 			grpname[i].name_size = id_entry->id_data_size;
9407836SJohn.Forte@Sun.COM 			bcopy(id_entry->id_data, grpname[i].name,
9417836SJohn.Forte@Sun.COM 			    id_entry->id_data_size);
9427836SJohn.Forte@Sun.COM 			id_entry = id_entry->id_next;
9437836SJohn.Forte@Sun.COM 		}
9447836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9457836SJohn.Forte@Sun.COM 		break;
9467836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_ENTRIES:
9477836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
9487836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
9497836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_ENTRIES:
9507836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
9517836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9527836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
9537836SJohn.Forte@Sun.COM 			ret = EINVAL;
9547836SJohn.Forte@Sun.COM 			break;
9557836SJohn.Forte@Sun.COM 		}
9567836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_ENTRIES) {
9577836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
9587836SJohn.Forte@Sun.COM 		}
9597836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9607836SJohn.Forte@Sun.COM 		id_entry = stmf_lookup_id(id_list, grpname->name_size,
9617836SJohn.Forte@Sun.COM 		    grpname->name);
9627836SJohn.Forte@Sun.COM 		if (!id_entry)
9637836SJohn.Forte@Sun.COM 			ret = ENODEV;
9647836SJohn.Forte@Sun.COM 		else {
9657836SJohn.Forte@Sun.COM 			stmf_ge_ident_t *grp_entry;
9667836SJohn.Forte@Sun.COM 			id_list = (stmf_id_list_t *)id_entry->id_impl_specific;
9677836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = id_list->id_count;
9687836SJohn.Forte@Sun.COM 			n = min(id_list->id_count,
9697836SJohn.Forte@Sun.COM 			    iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t));
9707836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = n;
9717836SJohn.Forte@Sun.COM 			id_entry = id_list->idl_head;
9727836SJohn.Forte@Sun.COM 			grp_entry = (stmf_ge_ident_t *)obuf;
9737836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
9747836SJohn.Forte@Sun.COM 				bcopy(id_entry->id_data, grp_entry,
9757836SJohn.Forte@Sun.COM 				    id_entry->id_data_size);
9767836SJohn.Forte@Sun.COM 				id_entry = id_entry->id_next;
9777836SJohn.Forte@Sun.COM 			}
9787836SJohn.Forte@Sun.COM 		}
9797836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9807836SJohn.Forte@Sun.COM 		break;
9817836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_VE_LIST:
9827836SJohn.Forte@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
9837836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9847836SJohn.Forte@Sun.COM 		id_entry = stmf_state.stmf_luid_list.idl_head;
9857836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)obuf;
9867836SJohn.Forte@Sun.COM 		while (id_entry) {
9877836SJohn.Forte@Sun.COM 			view_entry =
9887836SJohn.Forte@Sun.COM 			    (stmf_view_entry_t *)id_entry->id_impl_specific;
9897836SJohn.Forte@Sun.COM 			for (; view_entry; view_entry = view_entry->ve_next) {
9907836SJohn.Forte@Sun.COM 				ve->ve_ndx_valid = 1;
9917836SJohn.Forte@Sun.COM 				ve->ve_ndx = view_entry->ve_id;
9927836SJohn.Forte@Sun.COM 				ve->ve_lu_number_valid = 1;
9937836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
9947836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
9957836SJohn.Forte@Sun.COM 				    view_entry->ve_luid->id_data_size);
9967836SJohn.Forte@Sun.COM 				if (view_entry->ve_hg->id_data[0] == '*')
9977836SJohn.Forte@Sun.COM 					ve->ve_all_hosts = 1;
9987836SJohn.Forte@Sun.COM 				else
9997836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_hg->id_data,
10007836SJohn.Forte@Sun.COM 					    ve->ve_host_group.name,
10017836SJohn.Forte@Sun.COM 					    view_entry->ve_hg->id_data_size);
10027836SJohn.Forte@Sun.COM 				if (view_entry->ve_tg->id_data[0] == '*')
10037836SJohn.Forte@Sun.COM 					ve->ve_all_targets = 1;
10047836SJohn.Forte@Sun.COM 				else
10057836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_tg->id_data,
10067836SJohn.Forte@Sun.COM 					    ve->ve_target_group.name,
10077836SJohn.Forte@Sun.COM 					    view_entry->ve_tg->id_data_size);
10087836SJohn.Forte@Sun.COM 				iocd->stmf_obuf_nentries++;
10097836SJohn.Forte@Sun.COM 				if (iocd->stmf_obuf_nentries >= n)
10107836SJohn.Forte@Sun.COM 					break;
10117836SJohn.Forte@Sun.COM 			}
10127836SJohn.Forte@Sun.COM 			if (iocd->stmf_obuf_nentries >= n)
10137836SJohn.Forte@Sun.COM 				break;
10147836SJohn.Forte@Sun.COM 		}
10157836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10167836SJohn.Forte@Sun.COM 		break;
10177836SJohn.Forte@Sun.COM #endif
10187836SJohn.Forte@Sun.COM 	case STMF_IOCTL_LOAD_PP_DATA:
10197836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
10207836SJohn.Forte@Sun.COM 			ret = EACCES;
10217836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
10227836SJohn.Forte@Sun.COM 			break;
10237836SJohn.Forte@Sun.COM 		}
10247836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
10257836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
10267836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
10277836SJohn.Forte@Sun.COM 			ret = EINVAL;
10287836SJohn.Forte@Sun.COM 			break;
10297836SJohn.Forte@Sun.COM 		}
10307836SJohn.Forte@Sun.COM 		ret = stmf_load_ppd_ioctl(ppi);
10317836SJohn.Forte@Sun.COM 		break;
10327836SJohn.Forte@Sun.COM 
10337836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_PP_DATA:
10347836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
10357836SJohn.Forte@Sun.COM 			ret = EACCES;
10367836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
10377836SJohn.Forte@Sun.COM 			break;
10387836SJohn.Forte@Sun.COM 		}
10397836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
10407836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
10417836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
10427836SJohn.Forte@Sun.COM 			ret = EINVAL;
10437836SJohn.Forte@Sun.COM 			break;
10447836SJohn.Forte@Sun.COM 		}
10457836SJohn.Forte@Sun.COM 		ret = stmf_delete_ppd_ioctl(ppi);
10467836SJohn.Forte@Sun.COM 		break;
10477836SJohn.Forte@Sun.COM 
10487836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_TRACE:
10497836SJohn.Forte@Sun.COM 		stmf_trace_clear();
10507836SJohn.Forte@Sun.COM 		break;
10517836SJohn.Forte@Sun.COM 
10527836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_TRACE:
10537836SJohn.Forte@Sun.COM 		if (iocd->stmf_ibuf_size && ibuf) {
10547836SJohn.Forte@Sun.COM 			((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0;
10557836SJohn.Forte@Sun.COM 			stmf_trace("\nstradm", "%s\n", ibuf);
10567836SJohn.Forte@Sun.COM 		}
10577836SJohn.Forte@Sun.COM 		break;
10587836SJohn.Forte@Sun.COM 
10597836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE_POSITION:
10607836SJohn.Forte@Sun.COM 		if (obuf && (iocd->stmf_obuf_size > 3)) {
10617836SJohn.Forte@Sun.COM 			mutex_enter(&trace_buf_lock);
10627836SJohn.Forte@Sun.COM 			*((int *)obuf) = trace_buf_curndx;
10637836SJohn.Forte@Sun.COM 			mutex_exit(&trace_buf_lock);
10647836SJohn.Forte@Sun.COM 		} else {
10657836SJohn.Forte@Sun.COM 			ret = EINVAL;
10667836SJohn.Forte@Sun.COM 		}
10677836SJohn.Forte@Sun.COM 		break;
10687836SJohn.Forte@Sun.COM 
10697836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE:
10707836SJohn.Forte@Sun.COM 		if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) {
10717836SJohn.Forte@Sun.COM 			ret = EINVAL;
10727836SJohn.Forte@Sun.COM 			break;
10737836SJohn.Forte@Sun.COM 		}
10747836SJohn.Forte@Sun.COM 		i = *((int *)ibuf);
10757836SJohn.Forte@Sun.COM 		if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) >
10767836SJohn.Forte@Sun.COM 		    trace_buf_size)) {
10777836SJohn.Forte@Sun.COM 			ret = EINVAL;
10787836SJohn.Forte@Sun.COM 			break;
10797836SJohn.Forte@Sun.COM 		}
10807836SJohn.Forte@Sun.COM 		mutex_enter(&trace_buf_lock);
10817836SJohn.Forte@Sun.COM 		bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size);
10827836SJohn.Forte@Sun.COM 		mutex_exit(&trace_buf_lock);
10837836SJohn.Forte@Sun.COM 		break;
10847836SJohn.Forte@Sun.COM 
10857836SJohn.Forte@Sun.COM 	default:
10867836SJohn.Forte@Sun.COM 		ret = ENOTTY;
10877836SJohn.Forte@Sun.COM 	}
10887836SJohn.Forte@Sun.COM 
10897836SJohn.Forte@Sun.COM 	if (ret == 0) {
10907836SJohn.Forte@Sun.COM 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
10917836SJohn.Forte@Sun.COM 	} else if (iocd->stmf_error) {
10927836SJohn.Forte@Sun.COM 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
10937836SJohn.Forte@Sun.COM 	}
10947836SJohn.Forte@Sun.COM 	if (obuf) {
10957836SJohn.Forte@Sun.COM 		kmem_free(obuf, iocd->stmf_obuf_size);
10967836SJohn.Forte@Sun.COM 		obuf = NULL;
10977836SJohn.Forte@Sun.COM 	}
10987836SJohn.Forte@Sun.COM 	if (ibuf) {
10997836SJohn.Forte@Sun.COM 		kmem_free(ibuf, iocd->stmf_ibuf_size);
11007836SJohn.Forte@Sun.COM 		ibuf = NULL;
11017836SJohn.Forte@Sun.COM 	}
11027836SJohn.Forte@Sun.COM 	kmem_free(iocd, sizeof (stmf_iocdata_t));
11037836SJohn.Forte@Sun.COM 	return (ret);
11047836SJohn.Forte@Sun.COM }
11057836SJohn.Forte@Sun.COM 
11067836SJohn.Forte@Sun.COM static int
11077836SJohn.Forte@Sun.COM stmf_get_service_state()
11087836SJohn.Forte@Sun.COM {
11097836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
11107836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
11117836SJohn.Forte@Sun.COM 	int online = 0;
11127836SJohn.Forte@Sun.COM 	int offline = 0;
11137836SJohn.Forte@Sun.COM 	int onlining = 0;
11147836SJohn.Forte@Sun.COM 	int offlining = 0;
11157836SJohn.Forte@Sun.COM 
11167836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
11177836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
11187836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
11197836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE)
11207836SJohn.Forte@Sun.COM 			offline++;
11217836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINE)
11227836SJohn.Forte@Sun.COM 			online++;
11237836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINING)
11247836SJohn.Forte@Sun.COM 			onlining++;
11257836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_OFFLINING)
11267836SJohn.Forte@Sun.COM 			offlining++;
11277836SJohn.Forte@Sun.COM 	}
11287836SJohn.Forte@Sun.COM 
11297836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
11307836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
11317836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE)
11327836SJohn.Forte@Sun.COM 			offline++;
11337836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINE)
11347836SJohn.Forte@Sun.COM 			online++;
11357836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINING)
11367836SJohn.Forte@Sun.COM 			onlining++;
11377836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_OFFLINING)
11387836SJohn.Forte@Sun.COM 			offlining++;
11397836SJohn.Forte@Sun.COM 	}
11407836SJohn.Forte@Sun.COM 
11417836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
11427836SJohn.Forte@Sun.COM 		if (onlining)
11437836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINING);
11447836SJohn.Forte@Sun.COM 		else
11457836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINE);
11467836SJohn.Forte@Sun.COM 	}
11477836SJohn.Forte@Sun.COM 
11487836SJohn.Forte@Sun.COM 	if (offlining) {
11497836SJohn.Forte@Sun.COM 		return (STMF_STATE_OFFLINING);
11507836SJohn.Forte@Sun.COM 	}
11517836SJohn.Forte@Sun.COM 
11527836SJohn.Forte@Sun.COM 	return (STMF_STATE_OFFLINE);
11537836SJohn.Forte@Sun.COM }
11547836SJohn.Forte@Sun.COM 
11557836SJohn.Forte@Sun.COM static int
11567836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std)
11577836SJohn.Forte@Sun.COM {
11587836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
11597836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
11607836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssi;
11617836SJohn.Forte@Sun.COM 	int svc_state;
11627836SJohn.Forte@Sun.COM 
11637836SJohn.Forte@Sun.COM 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
11647836SJohn.Forte@Sun.COM 	ssi.st_additional_info = NULL;
11657836SJohn.Forte@Sun.COM 
11667836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
11677836SJohn.Forte@Sun.COM 	if (!stmf_state.stmf_exclusive_open) {
11687836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
11697836SJohn.Forte@Sun.COM 		return (EACCES);
11707836SJohn.Forte@Sun.COM 	}
11717836SJohn.Forte@Sun.COM 
11727836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
11737836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
11747836SJohn.Forte@Sun.COM 		return (EBUSY);
11757836SJohn.Forte@Sun.COM 	}
11767836SJohn.Forte@Sun.COM 
11777836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_ONLINE) &&
11787836SJohn.Forte@Sun.COM 	    (std->state != STMF_STATE_OFFLINE)) {
11797836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
11807836SJohn.Forte@Sun.COM 		return (EINVAL);
11817836SJohn.Forte@Sun.COM 	}
11827836SJohn.Forte@Sun.COM 
11837836SJohn.Forte@Sun.COM 	svc_state = stmf_get_service_state();
11847836SJohn.Forte@Sun.COM 	if ((svc_state == STMF_STATE_OFFLINING) ||
11857836SJohn.Forte@Sun.COM 	    (svc_state == STMF_STATE_ONLINING)) {
11867836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
11877836SJohn.Forte@Sun.COM 		return (EBUSY);
11887836SJohn.Forte@Sun.COM 	}
11897836SJohn.Forte@Sun.COM 
11907836SJohn.Forte@Sun.COM 	if (svc_state == STMF_STATE_OFFLINE) {
11917836SJohn.Forte@Sun.COM 		if (std->config_state == STMF_CONFIG_INIT) {
11927836SJohn.Forte@Sun.COM 			if (std->state != STMF_STATE_OFFLINE) {
11937836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
11947836SJohn.Forte@Sun.COM 				return (EINVAL);
11957836SJohn.Forte@Sun.COM 			}
11967836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT;
11977836SJohn.Forte@Sun.COM 			stmf_delete_all_ppds();
11987836SJohn.Forte@Sun.COM 			stmf_view_clear_config();
11997836SJohn.Forte@Sun.COM 			stmf_view_init();
12007836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
12017836SJohn.Forte@Sun.COM 			return (0);
12027836SJohn.Forte@Sun.COM 		}
12037836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
12047836SJohn.Forte@Sun.COM 			if (std->config_state != STMF_CONFIG_INIT_DONE) {
12057836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
12067836SJohn.Forte@Sun.COM 				return (EINVAL);
12077836SJohn.Forte@Sun.COM 			}
12087836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE;
12097836SJohn.Forte@Sun.COM 		}
12107836SJohn.Forte@Sun.COM 		if (std->state == STMF_STATE_OFFLINE) {
12117836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
12127836SJohn.Forte@Sun.COM 			return (0);
12137836SJohn.Forte@Sun.COM 		}
12147836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
12157836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
12167836SJohn.Forte@Sun.COM 			return (EINVAL);
12177836SJohn.Forte@Sun.COM 		}
12187836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
12197836SJohn.Forte@Sun.COM 		stmf_state.stmf_service_running = 1;
12207836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
12217836SJohn.Forte@Sun.COM 
12227836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
12237836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
12247836SJohn.Forte@Sun.COM 			if (ilport->ilport_prev_state != STMF_STATE_ONLINE)
12257836SJohn.Forte@Sun.COM 				continue;
12267836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE,
12277836SJohn.Forte@Sun.COM 					ilport->ilport_lport, &ssi);
12287836SJohn.Forte@Sun.COM 		}
12297836SJohn.Forte@Sun.COM 
12307836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
12317836SJohn.Forte@Sun.COM 		    ilu = ilu->ilu_next) {
12327836SJohn.Forte@Sun.COM 			if (ilu->ilu_prev_state != STMF_STATE_ONLINE)
12337836SJohn.Forte@Sun.COM 				continue;
12347836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi);
12357836SJohn.Forte@Sun.COM 		}
12367836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
12377836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
12387836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
12397836SJohn.Forte@Sun.COM 		return (0);
12407836SJohn.Forte@Sun.COM 	}
12417836SJohn.Forte@Sun.COM 
12427836SJohn.Forte@Sun.COM 	/* svc_state is STMF_STATE_ONLINE here */
12437836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_OFFLINE) ||
12447836SJohn.Forte@Sun.COM 	    (std->config_state == STMF_CONFIG_INIT)) {
12457836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
12467836SJohn.Forte@Sun.COM 		return (EACCES);
12477836SJohn.Forte@Sun.COM 	}
12487836SJohn.Forte@Sun.COM 
12497836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 1;
12507836SJohn.Forte@Sun.COM 	stmf_state.stmf_service_running = 0;
12517836SJohn.Forte@Sun.COM 	stmf_delete_all_ppds();
12527836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
12537836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
12547836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
12557836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE)
12567836SJohn.Forte@Sun.COM 			continue;
12577836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE,
12587836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, &ssi);
12597836SJohn.Forte@Sun.COM 	}
12607836SJohn.Forte@Sun.COM 
12617836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
12627836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
12637836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE)
12647836SJohn.Forte@Sun.COM 			continue;
12657836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi);
12667836SJohn.Forte@Sun.COM 	}
12677836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
12687836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 0;
12697836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
12707836SJohn.Forte@Sun.COM 	return (0);
12717836SJohn.Forte@Sun.COM }
12727836SJohn.Forte@Sun.COM 
12737836SJohn.Forte@Sun.COM static int
12747836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std)
12757836SJohn.Forte@Sun.COM {
12767836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
12777836SJohn.Forte@Sun.COM 	std->state = stmf_get_service_state();
12787836SJohn.Forte@Sun.COM 	std->config_state = stmf_state.stmf_config_state;
12797836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
12807836SJohn.Forte@Sun.COM 
12817836SJohn.Forte@Sun.COM 	return (0);
12827836SJohn.Forte@Sun.COM }
12837836SJohn.Forte@Sun.COM 
12847836SJohn.Forte@Sun.COM typedef struct {
12857836SJohn.Forte@Sun.COM 	void	*bp;	/* back pointer from internal struct to main struct */
12867836SJohn.Forte@Sun.COM 	int	alloc_size;
12877836SJohn.Forte@Sun.COM } __istmf_t;
12887836SJohn.Forte@Sun.COM 
12897836SJohn.Forte@Sun.COM typedef struct {
12907836SJohn.Forte@Sun.COM 	__istmf_t	*fp;	/* Framework private */
12917836SJohn.Forte@Sun.COM 	void		*cp;	/* Caller private */
12927836SJohn.Forte@Sun.COM 	void		*ss;	/* struct specific */
12937836SJohn.Forte@Sun.COM } __stmf_t;
12947836SJohn.Forte@Sun.COM 
12957836SJohn.Forte@Sun.COM static struct {
12967836SJohn.Forte@Sun.COM 	int shared;
12977836SJohn.Forte@Sun.COM 	int fw_private;
12987836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 },
12997836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_provider_t),
13007836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_provider_t) },
13017836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_port_provider_t),
13027836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_port_provider_t) },
13037836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_local_port_t),
13047836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_local_port_t) },
13057836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_t),
13067836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_t) },
13077836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_scsi_session_t),
13087836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_session_t) },
13097836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(scsi_task_t),
13107836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_task_t) },
13117836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_data_buf_t),
13127836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) },
13137836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_dbuf_store_t),
13147836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) }
13157836SJohn.Forte@Sun.COM 
13167836SJohn.Forte@Sun.COM };
13177836SJohn.Forte@Sun.COM 
13187836SJohn.Forte@Sun.COM void *
13197836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
13207836SJohn.Forte@Sun.COM {
13217836SJohn.Forte@Sun.COM 	int stmf_size;
13227836SJohn.Forte@Sun.COM 	int kmem_flag;
13237836SJohn.Forte@Sun.COM 	__stmf_t *sh;
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 	if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS))
13267836SJohn.Forte@Sun.COM 		return (NULL);
13277836SJohn.Forte@Sun.COM 
13287836SJohn.Forte@Sun.COM 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
13297836SJohn.Forte@Sun.COM 		kmem_flag = KM_NOSLEEP;
13307836SJohn.Forte@Sun.COM 	} else {
13317836SJohn.Forte@Sun.COM 		kmem_flag = KM_SLEEP;
13327836SJohn.Forte@Sun.COM 	}
13337836SJohn.Forte@Sun.COM 
13347836SJohn.Forte@Sun.COM 	additional_size = (additional_size + 7) & (~7);
13357836SJohn.Forte@Sun.COM 	stmf_size = stmf_sizes[struct_id].shared +
13367836SJohn.Forte@Sun.COM 		stmf_sizes[struct_id].fw_private + additional_size;
13377836SJohn.Forte@Sun.COM 
13387836SJohn.Forte@Sun.COM 	sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag);
13397836SJohn.Forte@Sun.COM 
13407836SJohn.Forte@Sun.COM 	if (sh == NULL)
13417836SJohn.Forte@Sun.COM 		return (NULL);
13427836SJohn.Forte@Sun.COM 
13437836SJohn.Forte@Sun.COM 	sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
13447836SJohn.Forte@Sun.COM 	sh->cp = GET_BYTE_OFFSET(sh->fp, stmf_sizes[struct_id].fw_private);
13457836SJohn.Forte@Sun.COM 
13467836SJohn.Forte@Sun.COM 	sh->fp->bp = sh;
13477836SJohn.Forte@Sun.COM 	/* Just store the total size instead of storing additional size */
13487836SJohn.Forte@Sun.COM 	sh->fp->alloc_size = stmf_size;
13497836SJohn.Forte@Sun.COM 
13507836SJohn.Forte@Sun.COM 	return (sh);
13517836SJohn.Forte@Sun.COM }
13527836SJohn.Forte@Sun.COM 
13537836SJohn.Forte@Sun.COM void
13547836SJohn.Forte@Sun.COM stmf_free(void *ptr)
13557836SJohn.Forte@Sun.COM {
13567836SJohn.Forte@Sun.COM 	__stmf_t *sh = (__stmf_t *)ptr;
13577836SJohn.Forte@Sun.COM 
13587836SJohn.Forte@Sun.COM 	/*
13597836SJohn.Forte@Sun.COM 	 * So far we dont need any struct specific processing. If such
13607836SJohn.Forte@Sun.COM 	 * a need ever arises, then store the struct id in the framework
13617836SJohn.Forte@Sun.COM 	 * private section and get it here as sh->fp->struct_id.
13627836SJohn.Forte@Sun.COM 	 */
13637836SJohn.Forte@Sun.COM 	kmem_free(ptr, sh->fp->alloc_size);
13647836SJohn.Forte@Sun.COM }
13657836SJohn.Forte@Sun.COM 
13667836SJohn.Forte@Sun.COM /*
13677836SJohn.Forte@Sun.COM  * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
13687836SJohn.Forte@Sun.COM  * framework and returns a pointer to framework private data for the lu.
13697836SJohn.Forte@Sun.COM  * Returns NULL if the lu was not found.
13707836SJohn.Forte@Sun.COM  */
13717836SJohn.Forte@Sun.COM stmf_i_lu_t *
13727836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu)
13737836SJohn.Forte@Sun.COM {
13747836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
13757836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
13767836SJohn.Forte@Sun.COM 
13777836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
13787836SJohn.Forte@Sun.COM 		if (ilu->ilu_lu == lu)
13797836SJohn.Forte@Sun.COM 			return (ilu);
13807836SJohn.Forte@Sun.COM 	}
13817836SJohn.Forte@Sun.COM 	return (NULL);
13827836SJohn.Forte@Sun.COM }
13837836SJohn.Forte@Sun.COM 
13847836SJohn.Forte@Sun.COM /*
13857836SJohn.Forte@Sun.COM  * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
13867836SJohn.Forte@Sun.COM  * framework and returns a pointer to framework private data for the lu.
13877836SJohn.Forte@Sun.COM  * Returns NULL if the lu was not found.
13887836SJohn.Forte@Sun.COM  */
13897836SJohn.Forte@Sun.COM stmf_i_local_port_t *
13907836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport)
13917836SJohn.Forte@Sun.COM {
13927836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
13937836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
13947836SJohn.Forte@Sun.COM 
13957836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
13967836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
13977836SJohn.Forte@Sun.COM 		if (ilport->ilport_lport == lport)
13987836SJohn.Forte@Sun.COM 			return (ilport);
13997836SJohn.Forte@Sun.COM 	}
14007836SJohn.Forte@Sun.COM 	return (NULL);
14017836SJohn.Forte@Sun.COM }
14027836SJohn.Forte@Sun.COM 
14037836SJohn.Forte@Sun.COM stmf_status_t
14047836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp)
14057836SJohn.Forte@Sun.COM {
14067836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
14077836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
14087836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
14097836SJohn.Forte@Sun.COM 
14107836SJohn.Forte@Sun.COM 	if (lp->lp_lpif_rev != LPIF_REV_1)
14117836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
14127836SJohn.Forte@Sun.COM 
14137836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14147836SJohn.Forte@Sun.COM 	ilp->ilp_next = stmf_state.stmf_ilplist;
14157836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilplist = ilp;
14167836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlps++;
14177836SJohn.Forte@Sun.COM 
14187836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
14197836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
14207836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, lp->lp_name) == 0) {
14217836SJohn.Forte@Sun.COM 			break;
14227836SJohn.Forte@Sun.COM 		}
14237836SJohn.Forte@Sun.COM 	}
14247836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
14257836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
14267836SJohn.Forte@Sun.COM 	}
14277836SJohn.Forte@Sun.COM 	ilp->ilp_ppd = ppd;
14287836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ilp;
14297836SJohn.Forte@Sun.COM 	if (lp->lp_cb == NULL)
14307836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
14317836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 1;
14327836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
14337836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
14347836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
14357836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14367836SJohn.Forte@Sun.COM 	lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
14377836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14387836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 0;
14397836SJohn.Forte@Sun.COM 
14407836SJohn.Forte@Sun.COM rlp_bail_out:
14417836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14427836SJohn.Forte@Sun.COM 
14437836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
14447836SJohn.Forte@Sun.COM }
14457836SJohn.Forte@Sun.COM 
14467836SJohn.Forte@Sun.COM stmf_status_t
14477836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp)
14487836SJohn.Forte@Sun.COM {
14497836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t	**ppilp;
14507836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
14517836SJohn.Forte@Sun.COM 
14527836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14537836SJohn.Forte@Sun.COM 	if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) {
14547836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
14557836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
14567836SJohn.Forte@Sun.COM 	}
14577836SJohn.Forte@Sun.COM 	for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL;
14587836SJohn.Forte@Sun.COM 	    ppilp = &((*ppilp)->ilp_next)) {
14597836SJohn.Forte@Sun.COM 		if (*ppilp == ilp) {
14607836SJohn.Forte@Sun.COM 			*ppilp = ilp->ilp_next;
14617836SJohn.Forte@Sun.COM 			stmf_state.stmf_nlps--;
14627836SJohn.Forte@Sun.COM 			if (ilp->ilp_ppd) {
14637836SJohn.Forte@Sun.COM 				ilp->ilp_ppd->ppd_provider = NULL;
14647836SJohn.Forte@Sun.COM 				ilp->ilp_ppd = NULL;
14657836SJohn.Forte@Sun.COM 			}
14667836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
14677836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
14687836SJohn.Forte@Sun.COM 		}
14697836SJohn.Forte@Sun.COM 	}
14707836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14717836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
14727836SJohn.Forte@Sun.COM }
14737836SJohn.Forte@Sun.COM 
14747836SJohn.Forte@Sun.COM stmf_status_t
14757836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp)
14767836SJohn.Forte@Sun.COM {
14777836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
14787836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
14797836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
14807836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
14817836SJohn.Forte@Sun.COM 
14827836SJohn.Forte@Sun.COM 	if (pp->pp_portif_rev != PORTIF_REV_1)
14837836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
14847836SJohn.Forte@Sun.COM 
14857836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14867836SJohn.Forte@Sun.COM 	ipp->ipp_next = stmf_state.stmf_ipplist;
14877836SJohn.Forte@Sun.COM 	stmf_state.stmf_ipplist = ipp;
14887836SJohn.Forte@Sun.COM 	stmf_state.stmf_npps++;
14897836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
14907836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
14917836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, pp->pp_name) == 0) {
14927836SJohn.Forte@Sun.COM 			break;
14937836SJohn.Forte@Sun.COM 		}
14947836SJohn.Forte@Sun.COM 	}
14957836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
14967836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
14977836SJohn.Forte@Sun.COM 	}
14987836SJohn.Forte@Sun.COM 	ipp->ipp_ppd = ppd;
14997836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ipp;
15007836SJohn.Forte@Sun.COM 	if (pp->pp_cb == NULL)
15017836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
15027836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 1;
15037836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
15047836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
15057836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
15067836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
15077836SJohn.Forte@Sun.COM 	pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
15087836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15097836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 0;
15107836SJohn.Forte@Sun.COM 
15117836SJohn.Forte@Sun.COM rpp_bail_out:
15127836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
15137836SJohn.Forte@Sun.COM 
15147836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
15157836SJohn.Forte@Sun.COM }
15167836SJohn.Forte@Sun.COM 
15177836SJohn.Forte@Sun.COM stmf_status_t
15187836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp)
15197836SJohn.Forte@Sun.COM {
15207836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
15217836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
15227836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t **ppipp;
15237836SJohn.Forte@Sun.COM 
15247836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15257836SJohn.Forte@Sun.COM 	if (ipp->ipp_npps || ipp->ipp_cb_in_progress) {
15267836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
15277836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
15287836SJohn.Forte@Sun.COM 	}
15297836SJohn.Forte@Sun.COM 	for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL;
15307836SJohn.Forte@Sun.COM 	    ppipp = &((*ppipp)->ipp_next)) {
15317836SJohn.Forte@Sun.COM 		if (*ppipp == ipp) {
15327836SJohn.Forte@Sun.COM 			*ppipp = ipp->ipp_next;
15337836SJohn.Forte@Sun.COM 			stmf_state.stmf_npps--;
15347836SJohn.Forte@Sun.COM 			if (ipp->ipp_ppd) {
15357836SJohn.Forte@Sun.COM 				ipp->ipp_ppd->ppd_provider = NULL;
15367836SJohn.Forte@Sun.COM 				ipp->ipp_ppd = NULL;
15377836SJohn.Forte@Sun.COM 			}
15387836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
15397836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
15407836SJohn.Forte@Sun.COM 		}
15417836SJohn.Forte@Sun.COM 	}
15427836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
15437836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
15447836SJohn.Forte@Sun.COM }
15457836SJohn.Forte@Sun.COM 
15467836SJohn.Forte@Sun.COM int
15477836SJohn.Forte@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi)
15487836SJohn.Forte@Sun.COM {
15497836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t		*ipp;
15507836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t		*ilp;
15517836SJohn.Forte@Sun.COM 	stmf_pp_data_t			*ppd;
15527836SJohn.Forte@Sun.COM 	nvlist_t			*nv;
15537836SJohn.Forte@Sun.COM 	int				s;
15547836SJohn.Forte@Sun.COM 	int				ret;
15557836SJohn.Forte@Sun.COM 
15567836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
15577836SJohn.Forte@Sun.COM 		return (EINVAL);
15587836SJohn.Forte@Sun.COM 	}
15597836SJohn.Forte@Sun.COM 
15607836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15617836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
15627836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
15637836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
15647836SJohn.Forte@Sun.COM 				continue;
15657836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
15667836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
15677836SJohn.Forte@Sun.COM 				continue;
15687836SJohn.Forte@Sun.COM 		}
15697836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
15707836SJohn.Forte@Sun.COM 			break;
15717836SJohn.Forte@Sun.COM 	}
15727836SJohn.Forte@Sun.COM 
15737836SJohn.Forte@Sun.COM 	if (ppd == NULL) {
15747836SJohn.Forte@Sun.COM 		/* New provider */
15757836SJohn.Forte@Sun.COM 		s = strlen(ppi->ppi_name);
15767836SJohn.Forte@Sun.COM 		if (s > 254) {
15777836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
15787836SJohn.Forte@Sun.COM 			return (EINVAL);
15797836SJohn.Forte@Sun.COM 		}
15807836SJohn.Forte@Sun.COM 		s += sizeof (stmf_pp_data_t) - 7;
15817836SJohn.Forte@Sun.COM 
15827836SJohn.Forte@Sun.COM 		ppd = kmem_zalloc(s, KM_NOSLEEP);
15837836SJohn.Forte@Sun.COM 		if (ppd == NULL) {
15847836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
15857836SJohn.Forte@Sun.COM 			return (ENOMEM);
15867836SJohn.Forte@Sun.COM 		}
15877836SJohn.Forte@Sun.COM 		ppd->ppd_alloc_size = s;
15887836SJohn.Forte@Sun.COM 		(void) strcpy(ppd->ppd_name, ppi->ppi_name);
15897836SJohn.Forte@Sun.COM 
15907836SJohn.Forte@Sun.COM 		/* See if this provider already exists */
15917836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
15927836SJohn.Forte@Sun.COM 			ppd->ppd_lu_provider = 1;
15937836SJohn.Forte@Sun.COM 			for (ilp = stmf_state.stmf_ilplist; ilp != NULL;
15947836SJohn.Forte@Sun.COM 			    ilp = ilp->ilp_next) {
15957836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
15967836SJohn.Forte@Sun.COM 				    ilp->ilp_lp->lp_name) == 0) {
15977836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ilp;
15987836SJohn.Forte@Sun.COM 					ilp->ilp_ppd = ppd;
15997836SJohn.Forte@Sun.COM 					break;
16007836SJohn.Forte@Sun.COM 				}
16017836SJohn.Forte@Sun.COM 			}
16027836SJohn.Forte@Sun.COM 		} else {
16037836SJohn.Forte@Sun.COM 			ppd->ppd_port_provider = 1;
16047836SJohn.Forte@Sun.COM 			for (ipp = stmf_state.stmf_ipplist; ipp != NULL;
16057836SJohn.Forte@Sun.COM 			    ipp = ipp->ipp_next) {
16067836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
16077836SJohn.Forte@Sun.COM 				    ipp->ipp_pp->pp_name) == 0) {
16087836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ipp;
16097836SJohn.Forte@Sun.COM 					ipp->ipp_ppd = ppd;
16107836SJohn.Forte@Sun.COM 					break;
16117836SJohn.Forte@Sun.COM 				}
16127836SJohn.Forte@Sun.COM 			}
16137836SJohn.Forte@Sun.COM 		}
16147836SJohn.Forte@Sun.COM 
16157836SJohn.Forte@Sun.COM 		/* Link this ppd in */
16167836SJohn.Forte@Sun.COM 		ppd->ppd_next = stmf_state.stmf_ppdlist;
16177836SJohn.Forte@Sun.COM 		stmf_state.stmf_ppdlist = ppd;
16187836SJohn.Forte@Sun.COM 	}
16197836SJohn.Forte@Sun.COM 
16207836SJohn.Forte@Sun.COM 	if ((ret = nvlist_unpack((char *)ppi->ppi_data,
16217836SJohn.Forte@Sun.COM 	    (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
16227836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
16237836SJohn.Forte@Sun.COM 		return (ret);
16247836SJohn.Forte@Sun.COM 	}
16257836SJohn.Forte@Sun.COM 
16267836SJohn.Forte@Sun.COM 	/* Free any existing lists and add this one to the ppd */
16277836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
16287836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
16297836SJohn.Forte@Sun.COM 	ppd->ppd_nv = nv;
16307836SJohn.Forte@Sun.COM 
16317836SJohn.Forte@Sun.COM 	/* If there is a provider registered, do the notifications */
16327836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
16337836SJohn.Forte@Sun.COM 		uint32_t cb_flags = 0;
16347836SJohn.Forte@Sun.COM 
16357836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
16367836SJohn.Forte@Sun.COM 			cb_flags |= STMF_PCB_STMF_ONLINING;
16377836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
16387836SJohn.Forte@Sun.COM 			ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider;
16397836SJohn.Forte@Sun.COM 			if (ilp->ilp_lp->lp_cb == NULL)
16407836SJohn.Forte@Sun.COM 				goto bail_out;
16417836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 1;
16427836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
16437836SJohn.Forte@Sun.COM 			ilp->ilp_lp->lp_cb(ilp->ilp_lp,
16447836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
16457836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
16467836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 0;
16477836SJohn.Forte@Sun.COM 		} else {
16487836SJohn.Forte@Sun.COM 			ipp = (stmf_i_port_provider_t *)ppd->ppd_provider;
16497836SJohn.Forte@Sun.COM 			if (ipp->ipp_pp->pp_cb == NULL)
16507836SJohn.Forte@Sun.COM 				goto bail_out;
16517836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 1;
16527836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
16537836SJohn.Forte@Sun.COM 			ipp->ipp_pp->pp_cb(ipp->ipp_pp,
16547836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
16557836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
16567836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 0;
16577836SJohn.Forte@Sun.COM 		}
16587836SJohn.Forte@Sun.COM 	}
16597836SJohn.Forte@Sun.COM 
16607836SJohn.Forte@Sun.COM bail_out:
16617836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16627836SJohn.Forte@Sun.COM 
16637836SJohn.Forte@Sun.COM 	return (0);
16647836SJohn.Forte@Sun.COM }
16657836SJohn.Forte@Sun.COM 
16667836SJohn.Forte@Sun.COM void
16677836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd)
16687836SJohn.Forte@Sun.COM {
16697836SJohn.Forte@Sun.COM 	stmf_pp_data_t **pppd;
16707836SJohn.Forte@Sun.COM 
16717836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
16727836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
16737836SJohn.Forte@Sun.COM 		if (ppd->ppd_lu_provider) {
16747836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
16757836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ilp_ppd = NULL;
16767836SJohn.Forte@Sun.COM 		} else {
16777836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
16787836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ipp_ppd = NULL;
16797836SJohn.Forte@Sun.COM 		}
16807836SJohn.Forte@Sun.COM 		ppd->ppd_provider = NULL;
16817836SJohn.Forte@Sun.COM 	}
16827836SJohn.Forte@Sun.COM 
16837836SJohn.Forte@Sun.COM 	for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL;
16847836SJohn.Forte@Sun.COM 			pppd = &((*pppd)->ppd_next)) {
16857836SJohn.Forte@Sun.COM 		if (*pppd == ppd)
16867836SJohn.Forte@Sun.COM 			break;
16877836SJohn.Forte@Sun.COM 	}
16887836SJohn.Forte@Sun.COM 
16897836SJohn.Forte@Sun.COM 	if (*pppd == NULL)
16907836SJohn.Forte@Sun.COM 		return;
16917836SJohn.Forte@Sun.COM 
16927836SJohn.Forte@Sun.COM 	*pppd = ppd->ppd_next;
16937836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
16947836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
16957836SJohn.Forte@Sun.COM 
16967836SJohn.Forte@Sun.COM 	kmem_free(ppd, ppd->ppd_alloc_size);
16977836SJohn.Forte@Sun.COM }
16987836SJohn.Forte@Sun.COM 
16997836SJohn.Forte@Sun.COM int
17007836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
17017836SJohn.Forte@Sun.COM {
17027836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
17037836SJohn.Forte@Sun.COM 	int ret = ENOENT;
17047836SJohn.Forte@Sun.COM 
17057836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
17067836SJohn.Forte@Sun.COM 		return (EINVAL);
17077836SJohn.Forte@Sun.COM 	}
17087836SJohn.Forte@Sun.COM 
17097836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
17107836SJohn.Forte@Sun.COM 
17117836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
17127836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
17137836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
17147836SJohn.Forte@Sun.COM 				continue;
17157836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
17167836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
17177836SJohn.Forte@Sun.COM 				continue;
17187836SJohn.Forte@Sun.COM 		}
17197836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
17207836SJohn.Forte@Sun.COM 			break;
17217836SJohn.Forte@Sun.COM 	}
17227836SJohn.Forte@Sun.COM 
17237836SJohn.Forte@Sun.COM 	if (ppd) {
17247836SJohn.Forte@Sun.COM 		ret = 0;
17257836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
17267836SJohn.Forte@Sun.COM 	}
17277836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
17287836SJohn.Forte@Sun.COM 
17297836SJohn.Forte@Sun.COM 	return (ret);
17307836SJohn.Forte@Sun.COM }
17317836SJohn.Forte@Sun.COM 
17327836SJohn.Forte@Sun.COM void
17337836SJohn.Forte@Sun.COM stmf_delete_all_ppds()
17347836SJohn.Forte@Sun.COM {
17357836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd, *nppd;
17367836SJohn.Forte@Sun.COM 
17377836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
17387836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) {
17397836SJohn.Forte@Sun.COM 		nppd = ppd->ppd_next;
17407836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
17417836SJohn.Forte@Sun.COM 	}
17427836SJohn.Forte@Sun.COM }
17437836SJohn.Forte@Sun.COM 
17447836SJohn.Forte@Sun.COM stmf_status_t
17457836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu)
17467836SJohn.Forte@Sun.COM {
17477836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
17487836SJohn.Forte@Sun.COM 	uint8_t *p1, *p2;
17497836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
17507836SJohn.Forte@Sun.COM 	stmf_id_data_t *luid;
17517836SJohn.Forte@Sun.COM 
17527836SJohn.Forte@Sun.COM 	if ((lu->lu_id->ident_type != ID_TYPE_NAA) ||
17537836SJohn.Forte@Sun.COM 	    (lu->lu_id->ident_length != 16) ||
17547836SJohn.Forte@Sun.COM 	    ((lu->lu_id->ident[0] & 0xf0) != 0x60)) {
17557836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
17567836SJohn.Forte@Sun.COM 	}
17577836SJohn.Forte@Sun.COM 	p1 = &lu->lu_id->ident[0];
17587836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
17597836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
17607836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
17617836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
17627836SJohn.Forte@Sun.COM 	}
17637836SJohn.Forte@Sun.COM 
17647836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
17657836SJohn.Forte@Sun.COM 		p2 = &ilu->ilu_lu->lu_id->ident[0];
17667836SJohn.Forte@Sun.COM 		if (bcmp(p1, p2, 16) == 0) {
17677836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17687836SJohn.Forte@Sun.COM 			return (STMF_ALREADY);
17697836SJohn.Forte@Sun.COM 		}
17707836SJohn.Forte@Sun.COM 	}
17717836SJohn.Forte@Sun.COM 
17727836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
17737836SJohn.Forte@Sun.COM 	luid = stmf_lookup_id(&stmf_state.stmf_luid_list,
17747836SJohn.Forte@Sun.COM 	    lu->lu_id->ident_length, lu->lu_id->ident);
17757836SJohn.Forte@Sun.COM 	if (luid) {
17767836SJohn.Forte@Sun.COM 		luid->id_pt_to_object = (void *)ilu;
17777836SJohn.Forte@Sun.COM 		ilu->ilu_luid = luid;
17787836SJohn.Forte@Sun.COM 	}
17797836SJohn.Forte@Sun.COM 	ilu->ilu_alias = NULL;
17807836SJohn.Forte@Sun.COM 
17817836SJohn.Forte@Sun.COM 	ilu->ilu_next = stmf_state.stmf_ilulist;
17827836SJohn.Forte@Sun.COM 	ilu->ilu_prev = NULL;
17837836SJohn.Forte@Sun.COM 	if (ilu->ilu_next)
17847836SJohn.Forte@Sun.COM 		ilu->ilu_next->ilu_prev = ilu;
17857836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilulist = ilu;
17867836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlus++;
17877836SJohn.Forte@Sun.COM 	if (lu->lu_lp) {
17887836SJohn.Forte@Sun.COM 		((stmf_i_lu_provider_t *)
17897836SJohn.Forte@Sun.COM 		    (lu->lu_lp->lp_stmf_private))->ilp_nlus++;
17907836SJohn.Forte@Sun.COM 	}
17917836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
17927836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
17937836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
17947836SJohn.Forte@Sun.COM 
17957836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lu can be brought online */
17967836SJohn.Forte@Sun.COM 	ilu->ilu_prev_state = STMF_STATE_ONLINE;
17977836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
17987836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
17997836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
18007836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci);
18017836SJohn.Forte@Sun.COM 	}
18027836SJohn.Forte@Sun.COM 
18037836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
18047836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
18057836SJohn.Forte@Sun.COM }
18067836SJohn.Forte@Sun.COM 
18077836SJohn.Forte@Sun.COM stmf_status_t
18087836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu)
18097836SJohn.Forte@Sun.COM {
18107836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
18117836SJohn.Forte@Sun.COM 
18127836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
18137836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
18147836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
18157836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
18167836SJohn.Forte@Sun.COM 	}
18177836SJohn.Forte@Sun.COM 	ilu = stmf_lookup_lu(lu);
18187836SJohn.Forte@Sun.COM 	if (ilu == NULL) {
18197836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
18207836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
18217836SJohn.Forte@Sun.COM 	}
18227836SJohn.Forte@Sun.COM 	if (ilu->ilu_state == STMF_STATE_OFFLINE) {
18237836SJohn.Forte@Sun.COM 		ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
18247836SJohn.Forte@Sun.COM 		while (ilu->ilu_flags & ILU_STALL_DEREGISTER) {
18257836SJohn.Forte@Sun.COM 			cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock);
18267836SJohn.Forte@Sun.COM 		}
18277836SJohn.Forte@Sun.COM 		if (ilu->ilu_ntasks) {
18287836SJohn.Forte@Sun.COM 			stmf_i_scsi_task_t *itask, *nitask;
18297836SJohn.Forte@Sun.COM 
18307836SJohn.Forte@Sun.COM 			nitask = ilu->ilu_tasks;
18317836SJohn.Forte@Sun.COM 			do {
18327836SJohn.Forte@Sun.COM 				itask = nitask;
18337836SJohn.Forte@Sun.COM 				nitask = itask->itask_lu_next;
18347836SJohn.Forte@Sun.COM 				lu->lu_task_free(itask->itask_task);
18357836SJohn.Forte@Sun.COM 				stmf_free(itask->itask_task);
18367836SJohn.Forte@Sun.COM 			} while (nitask != NULL);
18377836SJohn.Forte@Sun.COM 
18387836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = ilu->ilu_free_tasks = NULL;
18397836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0;
18407836SJohn.Forte@Sun.COM 		}
18417836SJohn.Forte@Sun.COM 
18427836SJohn.Forte@Sun.COM 		if (ilu->ilu_next)
18437836SJohn.Forte@Sun.COM 			ilu->ilu_next->ilu_prev = ilu->ilu_prev;
18447836SJohn.Forte@Sun.COM 		if (ilu->ilu_prev)
18457836SJohn.Forte@Sun.COM 			ilu->ilu_prev->ilu_next = ilu->ilu_next;
18467836SJohn.Forte@Sun.COM 		else
18477836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilulist = ilu->ilu_next;
18487836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlus--;
18497836SJohn.Forte@Sun.COM 
18507836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_draining) {
18517836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
18527836SJohn.Forte@Sun.COM 		}
18537836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_timing) {
18547836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
18557836SJohn.Forte@Sun.COM 		}
18567836SJohn.Forte@Sun.COM 		if (lu->lu_lp) {
18577836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
18587836SJohn.Forte@Sun.COM 			    (lu->lu_lp->lp_stmf_private))->ilp_nlus--;
18597836SJohn.Forte@Sun.COM 		}
18607836SJohn.Forte@Sun.COM 		if (ilu->ilu_luid) {
18617836SJohn.Forte@Sun.COM 			((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object =
18627836SJohn.Forte@Sun.COM 			    NULL;
18637836SJohn.Forte@Sun.COM 			ilu->ilu_luid = NULL;
18647836SJohn.Forte@Sun.COM 		}
18657836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl);
18667836SJohn.Forte@Sun.COM 	} else {
18677836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
18687836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
18697836SJohn.Forte@Sun.COM 	}
18707836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
18717836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
18727836SJohn.Forte@Sun.COM }
18737836SJohn.Forte@Sun.COM 
18747836SJohn.Forte@Sun.COM stmf_status_t
18757836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport)
18767836SJohn.Forte@Sun.COM {
18777836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
18787836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
18797836SJohn.Forte@Sun.COM 	int start_workers = 0;
18807836SJohn.Forte@Sun.COM 
18817836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
18827836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
18837836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
18847836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
18857836SJohn.Forte@Sun.COM 	}
18867836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
18877836SJohn.Forte@Sun.COM 	rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL);
18887836SJohn.Forte@Sun.COM 
18897836SJohn.Forte@Sun.COM 	ilport->ilport_next = stmf_state.stmf_ilportlist;
18907836SJohn.Forte@Sun.COM 	ilport->ilport_prev = NULL;
18917836SJohn.Forte@Sun.COM 	if (ilport->ilport_next)
18927836SJohn.Forte@Sun.COM 		ilport->ilport_next->ilport_prev = ilport;
18937836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilportlist = ilport;
18947836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlports++;
18957836SJohn.Forte@Sun.COM 	if (lport->lport_pp) {
18967836SJohn.Forte@Sun.COM 		((stmf_i_port_provider_t *)
18977836SJohn.Forte@Sun.COM 		    (lport->lport_pp->pp_stmf_private))->ipp_npps++;
18987836SJohn.Forte@Sun.COM 	}
18997836SJohn.Forte@Sun.COM 	ilport->ilport_tg =
19007836SJohn.Forte@Sun.COM 	    stmf_lookup_group_for_target(lport->lport_id->ident,
19017836SJohn.Forte@Sun.COM 		lport->lport_id->ident_length);
19027836SJohn.Forte@Sun.COM 	ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1);
19037836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl);
19047836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED) {
19057836SJohn.Forte@Sun.COM 		stmf_workers_state = STMF_WORKERS_ENABLING;
19067836SJohn.Forte@Sun.COM 		start_workers = 1;
19077836SJohn.Forte@Sun.COM 	}
19087836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
19097836SJohn.Forte@Sun.COM 
19107836SJohn.Forte@Sun.COM 	if (start_workers)
19117836SJohn.Forte@Sun.COM 		stmf_worker_init();
19127836SJohn.Forte@Sun.COM 
19137836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lport can be brought online */
19147836SJohn.Forte@Sun.COM 	ilport->ilport_prev_state = STMF_STATE_ONLINE;
19157836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
19167836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
19177836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
19187836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci);
19197836SJohn.Forte@Sun.COM 	}
19207836SJohn.Forte@Sun.COM 
19217836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
19227836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
19237836SJohn.Forte@Sun.COM }
19247836SJohn.Forte@Sun.COM 
19257836SJohn.Forte@Sun.COM stmf_status_t
19267836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport)
19277836SJohn.Forte@Sun.COM {
19287836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
19297836SJohn.Forte@Sun.COM 
19307836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
19317836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
19327836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
19337836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
19347836SJohn.Forte@Sun.COM 	}
19357836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
19367836SJohn.Forte@Sun.COM 	if (ilport->ilport_nsessions == 0) {
19377836SJohn.Forte@Sun.COM 		if (ilport->ilport_next)
19387836SJohn.Forte@Sun.COM 			ilport->ilport_next->ilport_prev = ilport->ilport_prev;
19397836SJohn.Forte@Sun.COM 		if (ilport->ilport_prev)
19407836SJohn.Forte@Sun.COM 			ilport->ilport_prev->ilport_next = ilport->ilport_next;
19417836SJohn.Forte@Sun.COM 		else
19427836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilportlist = ilport->ilport_next;
19437836SJohn.Forte@Sun.COM 		rw_destroy(&ilport->ilport_lock);
19447836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlports--;
19457836SJohn.Forte@Sun.COM 		if (lport->lport_pp) {
19467836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
19477836SJohn.Forte@Sun.COM 			    (lport->lport_pp->pp_stmf_private))->ipp_npps--;
19487836SJohn.Forte@Sun.COM 		}
19497836SJohn.Forte@Sun.COM 		ilport->ilport_tg = NULL;
19507836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl);
19517836SJohn.Forte@Sun.COM 	} else {
19527836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
19537836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
19547836SJohn.Forte@Sun.COM 	}
19557836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
19567836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
19577836SJohn.Forte@Sun.COM }
19587836SJohn.Forte@Sun.COM 
19597836SJohn.Forte@Sun.COM /*
19607836SJohn.Forte@Sun.COM  * Port provider has to make sure that register/deregister session and
19617836SJohn.Forte@Sun.COM  * port are serialized calls.
19627836SJohn.Forte@Sun.COM  */
19637836SJohn.Forte@Sun.COM stmf_status_t
19647836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
19657836SJohn.Forte@Sun.COM {
19667836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
19677836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
19687836SJohn.Forte@Sun.COM 	    lport->lport_stmf_private;
19697836SJohn.Forte@Sun.COM 	uint8_t		lun[8];
19707836SJohn.Forte@Sun.COM 
19717836SJohn.Forte@Sun.COM 	/*
19727836SJohn.Forte@Sun.COM 	 * Port state has to be online to register a scsi session. It is
19737836SJohn.Forte@Sun.COM 	 * possible that we started an offline operation and a new SCSI
19747836SJohn.Forte@Sun.COM 	 * session started at the same time (in that case also we are going
19757836SJohn.Forte@Sun.COM 	 * to fail the registeration). But any other state is simply
19767836SJohn.Forte@Sun.COM 	 * a bad port provider implementation.
19777836SJohn.Forte@Sun.COM 	 */
19787836SJohn.Forte@Sun.COM 	if (ilport->ilport_state != STMF_STATE_ONLINE) {
19797836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
19807836SJohn.Forte@Sun.COM 			stmf_trace(lport->lport_alias, "Port is trying to "
19817836SJohn.Forte@Sun.COM 			    "register a session while the state is neither "
19827836SJohn.Forte@Sun.COM 			    "online nor offlining");
19837836SJohn.Forte@Sun.COM 		}
19847836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
19857836SJohn.Forte@Sun.COM 	}
19867836SJohn.Forte@Sun.COM 	bzero(lun, 8);
19877836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
19887836SJohn.Forte@Sun.COM 	iss->iss_flags |= ISS_BEING_CREATED;
19897836SJohn.Forte@Sun.COM 
19907836SJohn.Forte@Sun.COM 	/* sessions use the ilport_lock. No separate lock is required */
19917836SJohn.Forte@Sun.COM 	iss->iss_lockp = &ilport->ilport_lock;
19927836SJohn.Forte@Sun.COM 	(void) stmf_session_create_lun_map(ilport, iss);
19937836SJohn.Forte@Sun.COM 
19947836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
19957836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions++;
19967836SJohn.Forte@Sun.COM 	iss->iss_next = ilport->ilport_ss_list;
19977836SJohn.Forte@Sun.COM 	ilport->ilport_ss_list = iss;
19987836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
19997836SJohn.Forte@Sun.COM 
20007836SJohn.Forte@Sun.COM 	iss->iss_creation_time = ddi_get_time();
20017836SJohn.Forte@Sun.COM 	ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1);
20027836SJohn.Forte@Sun.COM 	iss->iss_flags &= ~ISS_BEING_CREATED;
20037836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
20047836SJohn.Forte@Sun.COM }
20057836SJohn.Forte@Sun.COM 
20067836SJohn.Forte@Sun.COM void
20077836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
20087836SJohn.Forte@Sun.COM {
20097836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
20107836SJohn.Forte@Sun.COM 					lport->lport_stmf_private;
20117836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss, **ppss;
20127836SJohn.Forte@Sun.COM 	int found = 0;
20137836SJohn.Forte@Sun.COM 
20147836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
20157836SJohn.Forte@Sun.COM 	if (ss->ss_rport_alias) {
20167836SJohn.Forte@Sun.COM 		ss->ss_rport_alias = NULL;
20177836SJohn.Forte@Sun.COM 	}
20187836SJohn.Forte@Sun.COM 
20197836SJohn.Forte@Sun.COM try_dereg_ss_again:
20207836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
20217836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
20227836SJohn.Forte@Sun.COM 		~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
20237836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_EVENT_ACTIVE) {
20247836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
20257836SJohn.Forte@Sun.COM 		delay(1);
20267836SJohn.Forte@Sun.COM 		goto try_dereg_ss_again;
20277836SJohn.Forte@Sun.COM 	}
20287836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
20297836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
20307836SJohn.Forte@Sun.COM 	for (ppss = &ilport->ilport_ss_list; *ppss != NULL;
20317836SJohn.Forte@Sun.COM 	    ppss = &((*ppss)->iss_next)) {
20327836SJohn.Forte@Sun.COM 		if (iss == (*ppss)) {
20337836SJohn.Forte@Sun.COM 			*ppss = (*ppss)->iss_next;
20347836SJohn.Forte@Sun.COM 			found = 1;
20357836SJohn.Forte@Sun.COM 			break;
20367836SJohn.Forte@Sun.COM 		}
20377836SJohn.Forte@Sun.COM 	}
20387836SJohn.Forte@Sun.COM 	if (!found) {
20397836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "Deregister session called for non existent"
20407836SJohn.Forte@Sun.COM 		    " session");
20417836SJohn.Forte@Sun.COM 	}
20427836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions--;
20437836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
20447836SJohn.Forte@Sun.COM 
20457836SJohn.Forte@Sun.COM 	(void) stmf_session_destroy_lun_map(ilport, iss);
20467836SJohn.Forte@Sun.COM }
20477836SJohn.Forte@Sun.COM 
20487836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *
20497836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked)
20507836SJohn.Forte@Sun.COM {
20517836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
20527836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
20537836SJohn.Forte@Sun.COM 
20547836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
20557836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
20567836SJohn.Forte@Sun.COM 					ilport = ilport->ilport_next) {
20577836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
20587836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
20597836SJohn.Forte@Sun.COM 					iss = iss->iss_next) {
20607836SJohn.Forte@Sun.COM 			if (iss->iss_ss->ss_session_id == session_id) {
20617836SJohn.Forte@Sun.COM 				if (!stay_locked)
20627836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
20637836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
20647836SJohn.Forte@Sun.COM 				return (iss);
20657836SJohn.Forte@Sun.COM 			}
20667836SJohn.Forte@Sun.COM 		}
20677836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
20687836SJohn.Forte@Sun.COM 	}
20697836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
20707836SJohn.Forte@Sun.COM 	return (NULL);
20717836SJohn.Forte@Sun.COM }
20727836SJohn.Forte@Sun.COM 
20737836SJohn.Forte@Sun.COM void
20747836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
20757836SJohn.Forte@Sun.COM {
20767836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itlpp;
20777836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
20787836SJohn.Forte@Sun.COM 
20797836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED);
20807836SJohn.Forte@Sun.COM 
20817836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
20827836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
20837836SJohn.Forte@Sun.COM 	for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL;
20847836SJohn.Forte@Sun.COM 					itlpp = &(*itlpp)->itl_next) {
20857836SJohn.Forte@Sun.COM 		if ((*itlpp) == itl)
20867836SJohn.Forte@Sun.COM 			break;
20877836SJohn.Forte@Sun.COM 	}
20887836SJohn.Forte@Sun.COM 	ASSERT((*itlpp) != NULL);
20897836SJohn.Forte@Sun.COM 	*itlpp = itl->itl_next;
20907836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
20917836SJohn.Forte@Sun.COM 	lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle,
20927836SJohn.Forte@Sun.COM 				(uint32_t)itl->itl_hdlrm_reason);
20937836SJohn.Forte@Sun.COM 	kmem_free(itl, sizeof (*itl));
20947836SJohn.Forte@Sun.COM }
20957836SJohn.Forte@Sun.COM 
20967836SJohn.Forte@Sun.COM stmf_status_t
20977836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun,
20987836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
20997836SJohn.Forte@Sun.COM {
21007836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
21017836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
21027836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
21037836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
21047836SJohn.Forte@Sun.COM 	uint16_t n;
21057836SJohn.Forte@Sun.COM 
21067836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
21077836SJohn.Forte@Sun.COM 	if (ss == NULL) {
21087836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
21097836SJohn.Forte@Sun.COM 		if (iss == NULL)
21107836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
21117836SJohn.Forte@Sun.COM 	} else {
21127836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
21137836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
21147836SJohn.Forte@Sun.COM 	}
21157836SJohn.Forte@Sun.COM 
21167836SJohn.Forte@Sun.COM 	n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
21177836SJohn.Forte@Sun.COM 	lun_map_ent = (stmf_lun_map_ent_t *)
21187836SJohn.Forte@Sun.COM 			stmf_get_ent_from_map(iss->iss_sm, n);
21197836SJohn.Forte@Sun.COM 	if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) {
21207836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
21217836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
21227836SJohn.Forte@Sun.COM 	}
21237836SJohn.Forte@Sun.COM 	if (lun_map_ent->ent_itl_datap != NULL) {
21247836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
21257836SJohn.Forte@Sun.COM 		return (STMF_ALREADY);
21267836SJohn.Forte@Sun.COM 	}
21277836SJohn.Forte@Sun.COM 
21287836SJohn.Forte@Sun.COM 	itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP);
21297836SJohn.Forte@Sun.COM 	if (itl == NULL) {
21307836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
21317836SJohn.Forte@Sun.COM 		return (STMF_ALLOC_FAILURE);
21327836SJohn.Forte@Sun.COM 	}
21337836SJohn.Forte@Sun.COM 
21347836SJohn.Forte@Sun.COM 	itl->itl_counter = 1;
21357836SJohn.Forte@Sun.COM 	itl->itl_lun = n;
21367836SJohn.Forte@Sun.COM 	itl->itl_handle = itl_handle;
21377836SJohn.Forte@Sun.COM 	itl->itl_session = iss;
21387836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
21397836SJohn.Forte@Sun.COM 	itl->itl_next = ilu->ilu_itl_list;
21407836SJohn.Forte@Sun.COM 	ilu->ilu_itl_list = itl;
21417836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
21427836SJohn.Forte@Sun.COM 	lun_map_ent->ent_itl_datap = itl;
21437836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
21447836SJohn.Forte@Sun.COM 
21457836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
21467836SJohn.Forte@Sun.COM }
21477836SJohn.Forte@Sun.COM 
21487836SJohn.Forte@Sun.COM void
21497836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason)
21507836SJohn.Forte@Sun.COM {
21517836SJohn.Forte@Sun.COM 	uint8_t old, new;
21527836SJohn.Forte@Sun.COM 
21537836SJohn.Forte@Sun.COM 	do {
21547836SJohn.Forte@Sun.COM 		old = new = itl->itl_flags;
21557836SJohn.Forte@Sun.COM 		if (old & STMF_ITL_BEING_TERMINATED)
21567836SJohn.Forte@Sun.COM 			return;
21577836SJohn.Forte@Sun.COM 		new |= STMF_ITL_BEING_TERMINATED;
21587836SJohn.Forte@Sun.COM 	} while (atomic_cas_8(&itl->itl_flags, old, new) != old);
21597836SJohn.Forte@Sun.COM 	itl->itl_hdlrm_reason = hdlrm_reason;
21607836SJohn.Forte@Sun.COM 
21617836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_counter);
21627836SJohn.Forte@Sun.COM 
21637836SJohn.Forte@Sun.COM 	if (atomic_add_32_nv(&itl->itl_counter, -1))
21647836SJohn.Forte@Sun.COM 		return;
21657836SJohn.Forte@Sun.COM 
21667836SJohn.Forte@Sun.COM 	drv_usecwait(10);
21677836SJohn.Forte@Sun.COM 	if (itl->itl_counter)
21687836SJohn.Forte@Sun.COM 		return;
21697836SJohn.Forte@Sun.COM 
21707836SJohn.Forte@Sun.COM 	stmf_release_itl_handle(lu, itl);
21717836SJohn.Forte@Sun.COM }
21727836SJohn.Forte@Sun.COM 
21737836SJohn.Forte@Sun.COM stmf_status_t
21747836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu)
21757836SJohn.Forte@Sun.COM {
21767836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
21777836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
21787836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
21797836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
21807836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
21817836SJohn.Forte@Sun.COM 	uint32_t nmaps, nu;
21827836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itl_list;
21837836SJohn.Forte@Sun.COM 	int i;
21847836SJohn.Forte@Sun.COM 
21857836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
21867836SJohn.Forte@Sun.COM 
21877836SJohn.Forte@Sun.COM dereg_itl_start:;
21887836SJohn.Forte@Sun.COM 	nmaps = ilu->ilu_ref_cnt;
21897836SJohn.Forte@Sun.COM 	if (nmaps == 0)
21907836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
21917836SJohn.Forte@Sun.COM 	itl_list = (stmf_itl_data_t **)kmem_zalloc(
21927836SJohn.Forte@Sun.COM 			nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP);
21937836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
21947836SJohn.Forte@Sun.COM 	if (nmaps != ilu->ilu_ref_cnt) {
21957836SJohn.Forte@Sun.COM 		/* Something changed, start all over */
21967836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
21977836SJohn.Forte@Sun.COM 		kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
21987836SJohn.Forte@Sun.COM 		goto dereg_itl_start;
21997836SJohn.Forte@Sun.COM 	}
22007836SJohn.Forte@Sun.COM 	nu = 0;
22017836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
22027836SJohn.Forte@Sun.COM 				ilport = ilport->ilport_next) {
22037836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
22047836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
22057836SJohn.Forte@Sun.COM 					iss = iss->iss_next) {
22067836SJohn.Forte@Sun.COM 			lm = iss->iss_sm;
22077836SJohn.Forte@Sun.COM 			if (!lm)
22087836SJohn.Forte@Sun.COM 				continue;
22097836SJohn.Forte@Sun.COM 			for (i = 0; i < lm->lm_nentries; i++) {
22107836SJohn.Forte@Sun.COM 				if (lm->lm_plus[i] == NULL)
22117836SJohn.Forte@Sun.COM 					continue;
22127836SJohn.Forte@Sun.COM 				ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
22137836SJohn.Forte@Sun.COM 				if ((ent->ent_lu == lu) &&
22147836SJohn.Forte@Sun.COM 						(ent->ent_itl_datap)) {
22157836SJohn.Forte@Sun.COM 					itl_list[nu++] = ent->ent_itl_datap;
22167836SJohn.Forte@Sun.COM 					ent->ent_itl_datap = NULL;
22177836SJohn.Forte@Sun.COM 					if (nu == nmaps) {
22187836SJohn.Forte@Sun.COM 						rw_exit(&ilport->ilport_lock);
22197836SJohn.Forte@Sun.COM 						goto dai_scan_done;
22207836SJohn.Forte@Sun.COM 					}
22217836SJohn.Forte@Sun.COM 				}
22227836SJohn.Forte@Sun.COM 			} /* lun table for a session */
22237836SJohn.Forte@Sun.COM 		} /* sessions */
22247836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
22257836SJohn.Forte@Sun.COM 	} /* ports */
22267836SJohn.Forte@Sun.COM 
22277836SJohn.Forte@Sun.COM dai_scan_done:
22287836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
22297836SJohn.Forte@Sun.COM 
22307836SJohn.Forte@Sun.COM 	for (i = 0; i < nu; i++) {
22317836SJohn.Forte@Sun.COM 		stmf_do_itl_dereg(lu, itl_list[i],
22327836SJohn.Forte@Sun.COM 					STMF_ITL_REASON_DEREG_REQUEST);
22337836SJohn.Forte@Sun.COM 	}
22347836SJohn.Forte@Sun.COM 	kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
22357836SJohn.Forte@Sun.COM 
22367836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
22377836SJohn.Forte@Sun.COM }
22387836SJohn.Forte@Sun.COM 
22397836SJohn.Forte@Sun.COM stmf_status_t
22407836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
22417836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
22427836SJohn.Forte@Sun.COM {
22437836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
22447836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
22457836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
22467836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
22477836SJohn.Forte@Sun.COM 	int i;
22487836SJohn.Forte@Sun.COM 	uint16_t n;
22497836SJohn.Forte@Sun.COM 
22507836SJohn.Forte@Sun.COM 	if (ss == NULL) {
22517836SJohn.Forte@Sun.COM 		if (session_id == STMF_SESSION_ID_NONE)
22527836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
22537836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
22547836SJohn.Forte@Sun.COM 		if (iss == NULL)
22557836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
22567836SJohn.Forte@Sun.COM 	} else {
22577836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
22587836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
22597836SJohn.Forte@Sun.COM 	}
22607836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
22617836SJohn.Forte@Sun.COM 	if (lm == NULL) {
22627836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
22637836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
22647836SJohn.Forte@Sun.COM 	}
22657836SJohn.Forte@Sun.COM 
22667836SJohn.Forte@Sun.COM 	if (lun) {
22677836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
22687836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
22697836SJohn.Forte@Sun.COM 				stmf_get_ent_from_map(iss->iss_sm, n);
22707836SJohn.Forte@Sun.COM 	} else {
22717836SJohn.Forte@Sun.COM 		if (itl_handle == NULL) {
22727836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
22737836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
22747836SJohn.Forte@Sun.COM 		}
22757836SJohn.Forte@Sun.COM 		ent = NULL;
22767836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
22777836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
22787836SJohn.Forte@Sun.COM 				continue;
22797836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
22807836SJohn.Forte@Sun.COM 			if (ent->ent_itl_datap &&
22817836SJohn.Forte@Sun.COM 			    (ent->ent_itl_datap->itl_handle == itl_handle)) {
22827836SJohn.Forte@Sun.COM 				break;
22837836SJohn.Forte@Sun.COM 			}
22847836SJohn.Forte@Sun.COM 		}
22857836SJohn.Forte@Sun.COM 	}
22867836SJohn.Forte@Sun.COM 	if ((ent == NULL) || (ent->ent_lu != lu) ||
22877836SJohn.Forte@Sun.COM 			(ent->ent_itl_datap == NULL)) {
22887836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
22897836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
22907836SJohn.Forte@Sun.COM 	}
22917836SJohn.Forte@Sun.COM 	itl = ent->ent_itl_datap;
22927836SJohn.Forte@Sun.COM 	ent->ent_itl_datap = NULL;
22937836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
22947836SJohn.Forte@Sun.COM 	stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
22957836SJohn.Forte@Sun.COM 
22967836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
22977836SJohn.Forte@Sun.COM }
22987836SJohn.Forte@Sun.COM 
22997836SJohn.Forte@Sun.COM stmf_status_t
23007836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
23017836SJohn.Forte@Sun.COM     uint64_t session_id, void **itl_handle_retp)
23027836SJohn.Forte@Sun.COM {
23037836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
23047836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
23057836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
23067836SJohn.Forte@Sun.COM 	stmf_status_t ret;
23077836SJohn.Forte@Sun.COM 	int i;
23087836SJohn.Forte@Sun.COM 	uint16_t n;
23097836SJohn.Forte@Sun.COM 
23107836SJohn.Forte@Sun.COM 	if (ss == NULL) {
23117836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
23127836SJohn.Forte@Sun.COM 		if (iss == NULL)
23137836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
23147836SJohn.Forte@Sun.COM 	} else {
23157836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
23167836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
23177836SJohn.Forte@Sun.COM 	}
23187836SJohn.Forte@Sun.COM 
23197836SJohn.Forte@Sun.COM 	ent = NULL;
23207836SJohn.Forte@Sun.COM 	if (lun == NULL) {
23217836SJohn.Forte@Sun.COM 		lm = iss->iss_sm;
23227836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
23237836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
23247836SJohn.Forte@Sun.COM 				continue;
23257836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
23267836SJohn.Forte@Sun.COM 			if (ent->ent_lu == lu)
23277836SJohn.Forte@Sun.COM 				break;
23287836SJohn.Forte@Sun.COM 		}
23297836SJohn.Forte@Sun.COM 	} else {
23307836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
23317836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
23327836SJohn.Forte@Sun.COM 				stmf_get_ent_from_map(iss->iss_sm, n);
23337836SJohn.Forte@Sun.COM 		if (lu && (ent->ent_lu != lu))
23347836SJohn.Forte@Sun.COM 			ent = NULL;
23357836SJohn.Forte@Sun.COM 	}
23367836SJohn.Forte@Sun.COM 	if (ent && ent->ent_itl_datap) {
23377836SJohn.Forte@Sun.COM 		*itl_handle_retp = ent->ent_itl_datap->itl_handle;
23387836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
23397836SJohn.Forte@Sun.COM 	} else {
23407836SJohn.Forte@Sun.COM 		ret = STMF_NOT_FOUND;
23417836SJohn.Forte@Sun.COM 	}
23427836SJohn.Forte@Sun.COM 
23437836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
23447836SJohn.Forte@Sun.COM 	return (ret);
23457836SJohn.Forte@Sun.COM }
23467836SJohn.Forte@Sun.COM 
23477836SJohn.Forte@Sun.COM stmf_data_buf_t *
23487836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
23497836SJohn.Forte@Sun.COM     uint32_t flags)
23507836SJohn.Forte@Sun.COM {
23517836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
23527836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
23537836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
23547836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
23557836SJohn.Forte@Sun.COM 	uint8_t ndx;
23567836SJohn.Forte@Sun.COM 
23577836SJohn.Forte@Sun.COM 	ndx = stmf_first_zero[itask->itask_allocated_buf_map];
23587836SJohn.Forte@Sun.COM 	if (ndx == 0xff)
23597836SJohn.Forte@Sun.COM 		return (NULL);
23607836SJohn.Forte@Sun.COM 	dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf(
23617836SJohn.Forte@Sun.COM 	    task, size, pminsize, flags);
23627836SJohn.Forte@Sun.COM 	if (dbuf) {
23637836SJohn.Forte@Sun.COM 		task->task_cur_nbufs++;
23647836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map |= (1 << ndx);
23657836SJohn.Forte@Sun.COM 		dbuf->db_handle = ndx;
23667836SJohn.Forte@Sun.COM 		return (dbuf);
23677836SJohn.Forte@Sun.COM 	}
23687836SJohn.Forte@Sun.COM 
23697836SJohn.Forte@Sun.COM 	return (NULL);
23707836SJohn.Forte@Sun.COM }
23717836SJohn.Forte@Sun.COM 
23727836SJohn.Forte@Sun.COM void
23737836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf)
23747836SJohn.Forte@Sun.COM {
23757836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
23767836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
23777836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
23787836SJohn.Forte@Sun.COM 
23797836SJohn.Forte@Sun.COM 	itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle);
23807836SJohn.Forte@Sun.COM 	task->task_cur_nbufs--;
23817836SJohn.Forte@Sun.COM 	lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf);
23827836SJohn.Forte@Sun.COM }
23837836SJohn.Forte@Sun.COM 
23847836SJohn.Forte@Sun.COM stmf_data_buf_t *
23857836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h)
23867836SJohn.Forte@Sun.COM {
23877836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
23887836SJohn.Forte@Sun.COM 
23897836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
23907836SJohn.Forte@Sun.COM 	if (h > 3)
23917836SJohn.Forte@Sun.COM 		return (NULL);
23927836SJohn.Forte@Sun.COM 	return (itask->itask_dbufs[h]);
23937836SJohn.Forte@Sun.COM }
23947836SJohn.Forte@Sun.COM 
23957836SJohn.Forte@Sun.COM /* ARGSUSED */
23967836SJohn.Forte@Sun.COM struct scsi_task *
23977836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss,
23987836SJohn.Forte@Sun.COM 			uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id)
23997836SJohn.Forte@Sun.COM {
24007836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
24017836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
24027836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
24037836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
24047836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t **ppitask;
24057836SJohn.Forte@Sun.COM 	scsi_task_t *task;
24067836SJohn.Forte@Sun.COM 	uint64_t *p;
24077836SJohn.Forte@Sun.COM 	uint8_t	*l;
24087836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
24097836SJohn.Forte@Sun.COM 	uint16_t cdb_length;
24107836SJohn.Forte@Sun.COM 	uint16_t luNbr;
24117836SJohn.Forte@Sun.COM 	uint8_t new_task = 0;
24127836SJohn.Forte@Sun.COM 
24137836SJohn.Forte@Sun.COM 	/*
24147836SJohn.Forte@Sun.COM 	 * We allocate 7 extra bytes for CDB to provide a cdb pointer which
24157836SJohn.Forte@Sun.COM 	 * is guaranteed to be 8 byte aligned. Some LU providers like OSD
24167836SJohn.Forte@Sun.COM 	 * depend upon this alignment.
24177836SJohn.Forte@Sun.COM 	 */
24187836SJohn.Forte@Sun.COM 	if (cdb_length_in >= 16)
24197836SJohn.Forte@Sun.COM 		cdb_length = cdb_length_in + 7;
24207836SJohn.Forte@Sun.COM 	else
24217836SJohn.Forte@Sun.COM 		cdb_length = 16 + 7;
24227836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
24237836SJohn.Forte@Sun.COM 	luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
24247836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
24257836SJohn.Forte@Sun.COM 	lun_map_ent =
24267836SJohn.Forte@Sun.COM 	    (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr);
24277836SJohn.Forte@Sun.COM 	if (!lun_map_ent) {
24287836SJohn.Forte@Sun.COM 		lu = dlun0;
24297836SJohn.Forte@Sun.COM 	} else {
24307836SJohn.Forte@Sun.COM 		lu = lun_map_ent->ent_lu;
24317836SJohn.Forte@Sun.COM 	}
24327836SJohn.Forte@Sun.COM 	ilu = lu->lu_stmf_private;
24337836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
24347836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
24357836SJohn.Forte@Sun.COM 		return (NULL);
24367836SJohn.Forte@Sun.COM 	}
24377836SJohn.Forte@Sun.COM 	do {
24387836SJohn.Forte@Sun.COM 		if (ilu->ilu_free_tasks == NULL) {
24397836SJohn.Forte@Sun.COM 			new_task = 1;
24407836SJohn.Forte@Sun.COM 			break;
24417836SJohn.Forte@Sun.COM 		}
24427836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
24437836SJohn.Forte@Sun.COM 		for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) &&
24447836SJohn.Forte@Sun.COM 		    ((*ppitask)->itask_cdb_buf_size < cdb_length);
24457836SJohn.Forte@Sun.COM 		    ppitask = &((*ppitask)->itask_lu_free_next));
24467836SJohn.Forte@Sun.COM 		if (*ppitask) {
24477836SJohn.Forte@Sun.COM 			itask = *ppitask;
24487836SJohn.Forte@Sun.COM 			*ppitask = (*ppitask)->itask_lu_free_next;
24497836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_free--;
24507836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free)
24517836SJohn.Forte@Sun.COM 				ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
24527836SJohn.Forte@Sun.COM 		} else {
24537836SJohn.Forte@Sun.COM 			new_task = 1;
24547836SJohn.Forte@Sun.COM 		}
24557836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
24567836SJohn.Forte@Sun.COM 	/* CONSTCOND */
24577836SJohn.Forte@Sun.COM 	} while (0);
24587836SJohn.Forte@Sun.COM 
24597836SJohn.Forte@Sun.COM 	if (!new_task) {
24607836SJohn.Forte@Sun.COM 		task = itask->itask_task;
24617836SJohn.Forte@Sun.COM 		task->task_timeout = 0;
24627836SJohn.Forte@Sun.COM 		p = (uint64_t *)&task->task_flags;
24637836SJohn.Forte@Sun.COM 		*p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0;
24647836SJohn.Forte@Sun.COM 		itask->itask_ncmds = 0;
24657836SJohn.Forte@Sun.COM 	} else {
24667836SJohn.Forte@Sun.COM 		task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK,
24677836SJohn.Forte@Sun.COM 		    cdb_length, AF_FORCE_NOSLEEP);
24687836SJohn.Forte@Sun.COM 		if (task == NULL) {
24697836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
24707836SJohn.Forte@Sun.COM 			return (NULL);
24717836SJohn.Forte@Sun.COM 		}
24727836SJohn.Forte@Sun.COM 		task->task_lu = lu;
24737836SJohn.Forte@Sun.COM 		l = task->task_lun_no;
24747836SJohn.Forte@Sun.COM 		l[0] = lun[0];
24757836SJohn.Forte@Sun.COM 		l[1] = lun[1];
24767836SJohn.Forte@Sun.COM 		l[2] = lun[2];
24777836SJohn.Forte@Sun.COM 		l[3] = lun[3];
24787836SJohn.Forte@Sun.COM 		l[4] = lun[4];
24797836SJohn.Forte@Sun.COM 		l[5] = lun[5];
24807836SJohn.Forte@Sun.COM 		l[6] = lun[6];
24817836SJohn.Forte@Sun.COM 		l[7] = lun[7];
24827836SJohn.Forte@Sun.COM 		task->task_cdb = (uint8_t *)task->task_port_private;
24837836SJohn.Forte@Sun.COM 		if ((ulong_t)(task->task_cdb) & 7ul) {
24847836SJohn.Forte@Sun.COM 			task->task_cdb = (uint8_t *)(((ulong_t)
24857836SJohn.Forte@Sun.COM 			    (task->task_cdb) + 7ul) & ~(7ul));
24867836SJohn.Forte@Sun.COM 		}
24877836SJohn.Forte@Sun.COM 		itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
24887836SJohn.Forte@Sun.COM 		itask->itask_cdb_buf_size = cdb_length;
24897836SJohn.Forte@Sun.COM 	}
24907836SJohn.Forte@Sun.COM 	task->task_session = ss;
24917836SJohn.Forte@Sun.COM 	task->task_lport = lport;
24927836SJohn.Forte@Sun.COM 	task->task_cdb_length = cdb_length_in;
24937836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_TRANSITION;
24947836SJohn.Forte@Sun.COM 
24957836SJohn.Forte@Sun.COM 	if (new_task) {
24967836SJohn.Forte@Sun.COM 		if (lu->lu_task_alloc(task) != STMF_SUCCESS) {
24977836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
24987836SJohn.Forte@Sun.COM 			stmf_free(task);
24997836SJohn.Forte@Sun.COM 			return (NULL);
25007836SJohn.Forte@Sun.COM 		}
25017836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
25027836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
25037836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
25047836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
25057836SJohn.Forte@Sun.COM 			stmf_free(task);
25067836SJohn.Forte@Sun.COM 			return (NULL);
25077836SJohn.Forte@Sun.COM 		}
25087836SJohn.Forte@Sun.COM 		itask->itask_lu_next = ilu->ilu_tasks;
25097836SJohn.Forte@Sun.COM 		if (ilu->ilu_tasks)
25107836SJohn.Forte@Sun.COM 			ilu->ilu_tasks->itask_lu_prev = itask;
25117836SJohn.Forte@Sun.COM 		ilu->ilu_tasks = itask;
25127836SJohn.Forte@Sun.COM 		/* kmem_zalloc automatically makes itask->itask_lu_prev NULL */
25137836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks++;
25147836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
25157836SJohn.Forte@Sun.COM 	}
25167836SJohn.Forte@Sun.COM 
25177836SJohn.Forte@Sun.COM 	itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr;
25187836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, 1);
25197836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
25207836SJohn.Forte@Sun.COM 
25217836SJohn.Forte@Sun.COM 	if ((lun_map_ent != NULL) && ((itask->itask_itl_datap =
25227836SJohn.Forte@Sun.COM 	    lun_map_ent->ent_itl_datap) != NULL)) {
25237836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_itl_datap->itl_counter, 1);
25247836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle;
25257836SJohn.Forte@Sun.COM 	} else {
25267836SJohn.Forte@Sun.COM 		itask->itask_itl_datap = NULL;
25277836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = NULL;
25287836SJohn.Forte@Sun.COM 	}
25297836SJohn.Forte@Sun.COM 
25307836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
25317836SJohn.Forte@Sun.COM 	return (task);
25327836SJohn.Forte@Sun.COM }
25337836SJohn.Forte@Sun.COM 
25347836SJohn.Forte@Sun.COM void
25357836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task)
25367836SJohn.Forte@Sun.COM {
25377836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
25387836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
25397836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
25407836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
25417836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
25427836SJohn.Forte@Sun.COM 
25437836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
25447836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_FREE_LIST;
25457836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
25467836SJohn.Forte@Sun.COM 	itask->itask_lu_free_next = ilu->ilu_free_tasks;
25477836SJohn.Forte@Sun.COM 	ilu->ilu_free_tasks = itask;
25487836SJohn.Forte@Sun.COM 	ilu->ilu_ntasks_free++;
25497836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
25507836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, -1);
25517836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
25527836SJohn.Forte@Sun.COM }
25537836SJohn.Forte@Sun.COM 
25547836SJohn.Forte@Sun.COM void
25557836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu)
25567836SJohn.Forte@Sun.COM {
25577836SJohn.Forte@Sun.COM 	uint32_t	num_to_release, ndx;
25587836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
25597836SJohn.Forte@Sun.COM 	stmf_lu_t	*lu = ilu->ilu_lu;
25607836SJohn.Forte@Sun.COM 
25617836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free);
25627836SJohn.Forte@Sun.COM 
25637836SJohn.Forte@Sun.COM 	/* free half of the minimal free of the free tasks */
25647836SJohn.Forte@Sun.COM 	num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2;
25657836SJohn.Forte@Sun.COM 	if (!num_to_release) {
25667836SJohn.Forte@Sun.COM 		return;
25677836SJohn.Forte@Sun.COM 	}
25687836SJohn.Forte@Sun.COM 	for (ndx = 0; ndx < num_to_release; ndx++) {
25697836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
25707836SJohn.Forte@Sun.COM 		itask = ilu->ilu_free_tasks;
25717836SJohn.Forte@Sun.COM 		if (itask == NULL) {
25727836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
25737836SJohn.Forte@Sun.COM 			break;
25747836SJohn.Forte@Sun.COM 		}
25757836SJohn.Forte@Sun.COM 		ilu->ilu_free_tasks = itask->itask_lu_free_next;
25767836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_free--;
25777836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
25787836SJohn.Forte@Sun.COM 
25797836SJohn.Forte@Sun.COM 		lu->lu_task_free(itask->itask_task);
25807836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
25817836SJohn.Forte@Sun.COM 		if (itask->itask_lu_next)
25827836SJohn.Forte@Sun.COM 			itask->itask_lu_next->itask_lu_prev =
25837836SJohn.Forte@Sun.COM 			    itask->itask_lu_prev;
25847836SJohn.Forte@Sun.COM 		if (itask->itask_lu_prev)
25857836SJohn.Forte@Sun.COM 			itask->itask_lu_prev->itask_lu_next =
25867836SJohn.Forte@Sun.COM 			    itask->itask_lu_next;
25877836SJohn.Forte@Sun.COM 		else
25887836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = itask->itask_lu_next;
25897836SJohn.Forte@Sun.COM 
25907836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks--;
25917836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
25927836SJohn.Forte@Sun.COM 		stmf_free(itask->itask_task);
25937836SJohn.Forte@Sun.COM 	}
25947836SJohn.Forte@Sun.COM }
25957836SJohn.Forte@Sun.COM 
25967836SJohn.Forte@Sun.COM /*
25977836SJohn.Forte@Sun.COM  * Called with stmf_lock held
25987836SJohn.Forte@Sun.COM  */
25997836SJohn.Forte@Sun.COM void
26007836SJohn.Forte@Sun.COM stmf_check_freetask()
26017836SJohn.Forte@Sun.COM {
26027836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
26037836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
26047836SJohn.Forte@Sun.COM 
26057836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_draining may get changed after stmf_lock is released */
26067836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) {
26077836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
26087836SJohn.Forte@Sun.COM 		if (!ilu->ilu_ntasks_min_free) {
26097836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
26107836SJohn.Forte@Sun.COM 			continue;
26117836SJohn.Forte@Sun.COM 		}
26127836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
26137836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
26147836SJohn.Forte@Sun.COM 		stmf_task_lu_check_freelist(ilu);
26157836SJohn.Forte@Sun.COM 		/*
26167836SJohn.Forte@Sun.COM 		 * we do not care about the accuracy of
26177836SJohn.Forte@Sun.COM 		 * ilu_ntasks_min_free, so we don't lock here
26187836SJohn.Forte@Sun.COM 		 */
26197836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
26207836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
26217836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
26227836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
26237836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
26247836SJohn.Forte@Sun.COM 			break;
26257836SJohn.Forte@Sun.COM 	}
26267836SJohn.Forte@Sun.COM }
26277836SJohn.Forte@Sun.COM 
26287836SJohn.Forte@Sun.COM void
26297836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu)
26307836SJohn.Forte@Sun.COM {
26317836SJohn.Forte@Sun.COM 	clock_t l = ddi_get_lbolt();
26327836SJohn.Forte@Sun.COM 	clock_t ps = drv_usectohz(1000000);
26337836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
26347836SJohn.Forte@Sun.COM 	scsi_task_t *task;
26357836SJohn.Forte@Sun.COM 	uint32_t to;
26367836SJohn.Forte@Sun.COM 
26377836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
26387836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
26397836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
26407836SJohn.Forte@Sun.COM 		if (itask->itask_flags & (ITASK_IN_FREE_LIST |
26417836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) {
26427836SJohn.Forte@Sun.COM 			continue;
26437836SJohn.Forte@Sun.COM 		}
26447836SJohn.Forte@Sun.COM 		task = itask->itask_task;
26457836SJohn.Forte@Sun.COM 		if (task->task_timeout == 0)
26467836SJohn.Forte@Sun.COM 			to = stmf_default_task_timeout;
26477836SJohn.Forte@Sun.COM 		else
26487836SJohn.Forte@Sun.COM 			to = task->task_timeout;
26497836SJohn.Forte@Sun.COM 		if ((itask->itask_start_time + (to * ps)) > l)
26507836SJohn.Forte@Sun.COM 			continue;
26517836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
26527836SJohn.Forte@Sun.COM 		    STMF_TIMEOUT, NULL);
26537836SJohn.Forte@Sun.COM 	}
26547836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
26557836SJohn.Forte@Sun.COM }
26567836SJohn.Forte@Sun.COM 
26577836SJohn.Forte@Sun.COM /*
26587836SJohn.Forte@Sun.COM  * Called with stmf_lock held
26597836SJohn.Forte@Sun.COM  */
26607836SJohn.Forte@Sun.COM void
26617836SJohn.Forte@Sun.COM stmf_check_ilu_timing()
26627836SJohn.Forte@Sun.COM {
26637836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
26647836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
26657836SJohn.Forte@Sun.COM 
26667836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_timing may get changed after stmf_lock is released */
26677836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) {
26687836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
26697836SJohn.Forte@Sun.COM 		if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) {
26707836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr2 == 0) {
26717836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2;
26727836SJohn.Forte@Sun.COM 				continue;
26737836SJohn.Forte@Sun.COM 			}
26747836SJohn.Forte@Sun.COM 		} else {
26757836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr1 == 0) {
26767836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
26777836SJohn.Forte@Sun.COM 				continue;
26787836SJohn.Forte@Sun.COM 			}
26797836SJohn.Forte@Sun.COM 		}
26807836SJohn.Forte@Sun.COM 		/*
26817836SJohn.Forte@Sun.COM 		 * If we are here then it means that there is some slowdown
26827836SJohn.Forte@Sun.COM 		 * in tasks on this lu. We need to check.
26837836SJohn.Forte@Sun.COM 		 */
26847836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
26857836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
26867836SJohn.Forte@Sun.COM 		stmf_do_ilu_timeouts(ilu);
26877836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
26887836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
26897836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
26907836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
26917836SJohn.Forte@Sun.COM 			break;
26927836SJohn.Forte@Sun.COM 	}
26937836SJohn.Forte@Sun.COM }
26947836SJohn.Forte@Sun.COM 
26957836SJohn.Forte@Sun.COM /*
26967836SJohn.Forte@Sun.COM  * Kills all tasks on a lu except tm_task
26977836SJohn.Forte@Sun.COM  */
26987836SJohn.Forte@Sun.COM void
26997836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s)
27007836SJohn.Forte@Sun.COM {
27017836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
27027836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
27037836SJohn.Forte@Sun.COM 
27047836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
27057836SJohn.Forte@Sun.COM 
27067836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
27077836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
27087836SJohn.Forte@Sun.COM 		if (itask->itask_flags & ITASK_IN_FREE_LIST)
27097836SJohn.Forte@Sun.COM 			continue;
27107836SJohn.Forte@Sun.COM 		if (itask->itask_task == tm_task)
27117836SJohn.Forte@Sun.COM 			continue;
27127836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL);
27137836SJohn.Forte@Sun.COM 	}
27147836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
27157836SJohn.Forte@Sun.COM }
27167836SJohn.Forte@Sun.COM 
27177836SJohn.Forte@Sun.COM void
27187836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport)
27197836SJohn.Forte@Sun.COM {
27207836SJohn.Forte@Sun.COM 	int i;
27217836SJohn.Forte@Sun.COM 	uint8_t map;
27227836SJohn.Forte@Sun.COM 
27237836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
27247836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
27257836SJohn.Forte@Sun.COM 			if (map & 1) {
27267836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
27277836SJohn.Forte@Sun.COM 
27287836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
27297836SJohn.Forte@Sun.COM 				if (dbuf->db_lu_private) {
27307836SJohn.Forte@Sun.COM 					dbuf->db_lu_private = NULL;
27317836SJohn.Forte@Sun.COM 				}
27327836SJohn.Forte@Sun.COM 				lport->lport_ds->ds_free_data_buf(
27337836SJohn.Forte@Sun.COM 				    lport->lport_ds, dbuf);
27347836SJohn.Forte@Sun.COM 			}
27357836SJohn.Forte@Sun.COM 			map >>= 1;
27367836SJohn.Forte@Sun.COM 		}
27377836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
27387836SJohn.Forte@Sun.COM 	}
27397836SJohn.Forte@Sun.COM }
27407836SJohn.Forte@Sun.COM 
27417836SJohn.Forte@Sun.COM void
27427836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task)
27437836SJohn.Forte@Sun.COM {
27447836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
27457836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
27467836SJohn.Forte@Sun.COM 					task->task_stmf_private;
27477836SJohn.Forte@Sun.COM 
27487836SJohn.Forte@Sun.COM 	stmf_free_task_bufs(itask, lport);
27497836SJohn.Forte@Sun.COM 	if (itask->itask_itl_datap) {
27507836SJohn.Forte@Sun.COM 		if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter,
27517836SJohn.Forte@Sun.COM 		    -1) == 0) {
27527836SJohn.Forte@Sun.COM 			stmf_release_itl_handle(task->task_lu,
27537836SJohn.Forte@Sun.COM 						itask->itask_itl_datap);
27547836SJohn.Forte@Sun.COM 		}
27557836SJohn.Forte@Sun.COM 	}
27567836SJohn.Forte@Sun.COM 	lport->lport_task_free(task);
27577836SJohn.Forte@Sun.COM 	if (itask->itask_worker) {
27587836SJohn.Forte@Sun.COM 		atomic_add_32(&stmf_cur_ntasks, -1);
27597836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_worker->worker_ref_count, -1);
27607836SJohn.Forte@Sun.COM 	}
27617836SJohn.Forte@Sun.COM 	/*
27627836SJohn.Forte@Sun.COM 	 * After calling stmf_task_lu_free, the task pointer can no longer
27637836SJohn.Forte@Sun.COM 	 * be trusted.
27647836SJohn.Forte@Sun.COM 	 */
27657836SJohn.Forte@Sun.COM 	stmf_task_lu_free(task);
27667836SJohn.Forte@Sun.COM }
27677836SJohn.Forte@Sun.COM 
27687836SJohn.Forte@Sun.COM void
27697836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
27707836SJohn.Forte@Sun.COM {
27717836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
27727836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
27737836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
27747836SJohn.Forte@Sun.COM 	int nv;
27757836SJohn.Forte@Sun.COM 	uint32_t old, new;
27767836SJohn.Forte@Sun.COM 	uint32_t ct;
27777836SJohn.Forte@Sun.COM 	stmf_worker_t *w, *w1;
27787836SJohn.Forte@Sun.COM 	uint8_t tm;
27797836SJohn.Forte@Sun.COM 
27807836SJohn.Forte@Sun.COM 	if (task->task_max_nbufs > 4)
27817836SJohn.Forte@Sun.COM 		task->task_max_nbufs = 4;
27827836SJohn.Forte@Sun.COM 	task->task_cur_nbufs = 0;
27837836SJohn.Forte@Sun.COM 	/* Latest value of currently running tasks */
27847836SJohn.Forte@Sun.COM 	ct = atomic_add_32_nv(&stmf_cur_ntasks, 1);
27857836SJohn.Forte@Sun.COM 
27867836SJohn.Forte@Sun.COM 	/* Select the next worker using round robin */
27877836SJohn.Forte@Sun.COM 	nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1);
27887836SJohn.Forte@Sun.COM 	if (nv >= stmf_nworkers_accepting_cmds) {
27897836SJohn.Forte@Sun.COM 		int s = nv;
27907836SJohn.Forte@Sun.COM 		do {
27917836SJohn.Forte@Sun.COM 			nv -= stmf_nworkers_accepting_cmds;
27927836SJohn.Forte@Sun.COM 		} while (nv >= stmf_nworkers_accepting_cmds);
27937836SJohn.Forte@Sun.COM 		if (nv < 0)
27947836SJohn.Forte@Sun.COM 			nv = 0;
27957836SJohn.Forte@Sun.COM 		/* Its ok if this cas fails */
27967836SJohn.Forte@Sun.COM 		(void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter,
27977836SJohn.Forte@Sun.COM 		    s, nv);
27987836SJohn.Forte@Sun.COM 	}
27997836SJohn.Forte@Sun.COM 	w = &stmf_workers[nv];
28007836SJohn.Forte@Sun.COM 
28017836SJohn.Forte@Sun.COM 	/*
28027836SJohn.Forte@Sun.COM 	 * A worker can be pinned by interrupt. So select the next one
28037836SJohn.Forte@Sun.COM 	 * if it has lower load.
28047836SJohn.Forte@Sun.COM 	 */
28057836SJohn.Forte@Sun.COM 	if ((nv + 1) >= stmf_nworkers_accepting_cmds) {
28067836SJohn.Forte@Sun.COM 		w1 = stmf_workers;
28077836SJohn.Forte@Sun.COM 	} else {
28087836SJohn.Forte@Sun.COM 		w1 = &stmf_workers[nv + 1];
28097836SJohn.Forte@Sun.COM 	}
28107836SJohn.Forte@Sun.COM 	if (w1->worker_queue_depth < w->worker_queue_depth)
28117836SJohn.Forte@Sun.COM 		w = w1;
28127836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
28137836SJohn.Forte@Sun.COM 	if (((w->worker_flags & STMF_WORKER_STARTED) == 0) ||
28147836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
28157836SJohn.Forte@Sun.COM 		/*
28167836SJohn.Forte@Sun.COM 		 * Maybe we are in the middle of a change. Just go to
28177836SJohn.Forte@Sun.COM 		 * the 1st worker.
28187836SJohn.Forte@Sun.COM 		 */
28197836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
28207836SJohn.Forte@Sun.COM 		w = stmf_workers;
28217836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
28227836SJohn.Forte@Sun.COM 	}
28237836SJohn.Forte@Sun.COM 	itask->itask_worker = w;
28247836SJohn.Forte@Sun.COM 	/*
28257836SJohn.Forte@Sun.COM 	 * Track max system load inside the worker as we already have the
28267836SJohn.Forte@Sun.COM 	 * worker lock (no point implementing another lock). The service
28277836SJohn.Forte@Sun.COM 	 * thread will do the comparisons and figure out the max overall
28287836SJohn.Forte@Sun.COM 	 * system load.
28297836SJohn.Forte@Sun.COM 	 */
28307836SJohn.Forte@Sun.COM 	if (w->worker_max_sys_qdepth_pu < ct)
28317836SJohn.Forte@Sun.COM 		w->worker_max_sys_qdepth_pu = ct;
28327836SJohn.Forte@Sun.COM 
28337836SJohn.Forte@Sun.COM 	do {
28347836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
28357836SJohn.Forte@Sun.COM 		new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE;
28367836SJohn.Forte@Sun.COM 		if (task->task_mgmt_function) {
28377836SJohn.Forte@Sun.COM 			tm = task->task_mgmt_function;
28387836SJohn.Forte@Sun.COM 			if ((tm == TM_TARGET_RESET) ||
28397836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_COLD_RESET) ||
28407836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_WARM_RESET)) {
28417836SJohn.Forte@Sun.COM 				new |= ITASK_DEFAULT_HANDLING;
28427836SJohn.Forte@Sun.COM 			}
28437836SJohn.Forte@Sun.COM 		} else if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
28447836SJohn.Forte@Sun.COM 			new |= ITASK_DEFAULT_HANDLING;
28457836SJohn.Forte@Sun.COM 		}
28467836SJohn.Forte@Sun.COM 		new &= ~ITASK_IN_TRANSITION;
28477836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
28487836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
28497836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
28507836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
28517836SJohn.Forte@Sun.COM 	} else {
28527836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
28537836SJohn.Forte@Sun.COM 	}
28547836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
28557836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
28567836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
28577836SJohn.Forte@Sun.COM 	}
28587836SJohn.Forte@Sun.COM 	atomic_add_32(&w->worker_ref_count, 1);
28597836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK;
28607836SJohn.Forte@Sun.COM 	itask->itask_ncmds = 1;
28617836SJohn.Forte@Sun.COM 	if (dbuf) {
28627836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 1;
28637836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = dbuf;
28647836SJohn.Forte@Sun.COM 		dbuf->db_handle = 0;
28657836SJohn.Forte@Sun.COM 	} else {
28667836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
28677836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = NULL;
28687836SJohn.Forte@Sun.COM 	}
28697836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
28707836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
28717836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
28727836SJohn.Forte@Sun.COM 
28737836SJohn.Forte@Sun.COM 	/*
28747836SJohn.Forte@Sun.COM 	 * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE
28757836SJohn.Forte@Sun.COM 	 * was set between checking of ILU_RESET_ACTIVE and clearing of the
28767836SJohn.Forte@Sun.COM 	 * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here.
28777836SJohn.Forte@Sun.COM 	 */
28787836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
28797836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL);
28807836SJohn.Forte@Sun.COM 	}
28817836SJohn.Forte@Sun.COM }
28827836SJohn.Forte@Sun.COM 
28837836SJohn.Forte@Sun.COM /*
28847836SJohn.Forte@Sun.COM  * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++
28857836SJohn.Forte@Sun.COM  * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already
28867836SJohn.Forte@Sun.COM  * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot
28877836SJohn.Forte@Sun.COM  * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course
28887836SJohn.Forte@Sun.COM  * the LU will make this call only if we call the LU's abort entry point.
28897836SJohn.Forte@Sun.COM  * we will only call that entry point if ITASK_KNOWN_TO_LU was set.
28907836SJohn.Forte@Sun.COM  *
28917836SJohn.Forte@Sun.COM  * Same logic applies for the port.
28927836SJohn.Forte@Sun.COM  *
28937836SJohn.Forte@Sun.COM  * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU
28947836SJohn.Forte@Sun.COM  * and KNOWN_TO_TGT_PORT are reset.
28957836SJohn.Forte@Sun.COM  *
28967836SJohn.Forte@Sun.COM  * +++++++++++++++++++++++++++++++++++++++++++++++
28977836SJohn.Forte@Sun.COM  */
28987836SJohn.Forte@Sun.COM 
28997836SJohn.Forte@Sun.COM stmf_status_t
29007836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
29017836SJohn.Forte@Sun.COM {
29027836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
29037836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
29047836SJohn.Forte@Sun.COM 
29057836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
29067836SJohn.Forte@Sun.COM 		uint32_t new, old;
29077836SJohn.Forte@Sun.COM 		do {
29087836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
29097836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
29107836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
29117836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
29127836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
29137836SJohn.Forte@Sun.COM 	}
29147836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
29157836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
29167836SJohn.Forte@Sun.COM #ifdef	DEBUG
29177836SJohn.Forte@Sun.COM 	if (stmf_drop_buf_counter > 0) {
29187836SJohn.Forte@Sun.COM 		if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter,
29197836SJohn.Forte@Sun.COM 								-1) == 1)
29207836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
29217836SJohn.Forte@Sun.COM 	}
29227836SJohn.Forte@Sun.COM #endif
29237836SJohn.Forte@Sun.COM 	return (task->task_lport->lport_xfer_data(task, dbuf, ioflags));
29247836SJohn.Forte@Sun.COM }
29257836SJohn.Forte@Sun.COM 
29267836SJohn.Forte@Sun.COM void
29277836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof)
29287836SJohn.Forte@Sun.COM {
29297836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
29307836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
29317836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
29327836SJohn.Forte@Sun.COM 	uint32_t new, old;
29337836SJohn.Forte@Sun.COM 	uint8_t update_queue_flags, free_it, queue_it;
29347836SJohn.Forte@Sun.COM 
29357836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
29367836SJohn.Forte@Sun.COM 	do {
29377836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
29387836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
29397836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
29407836SJohn.Forte@Sun.COM 			return;
29417836SJohn.Forte@Sun.COM 		}
29427836SJohn.Forte@Sun.COM 		free_it = 0;
29437836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
29447836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
29457836SJohn.Forte@Sun.COM 			task->task_completion_status = dbuf->db_xfer_status;
29467836SJohn.Forte@Sun.COM 			free_it = 1;
29477836SJohn.Forte@Sun.COM 		}
29487836SJohn.Forte@Sun.COM 		/*
29497836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
29507836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
29517836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
29527836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
29537836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
29547836SJohn.Forte@Sun.COM 		 * free this task.
29557836SJohn.Forte@Sun.COM 		 */
29567836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
29577836SJohn.Forte@Sun.COM 			free_it = 0;
29587836SJohn.Forte@Sun.COM 			update_queue_flags = 1;
29597836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
29607836SJohn.Forte@Sun.COM 				queue_it = 0;
29617836SJohn.Forte@Sun.COM 			} else {
29627836SJohn.Forte@Sun.COM 				queue_it = 1;
29637836SJohn.Forte@Sun.COM 				new |= ITASK_IN_WORKER_QUEUE;
29647836SJohn.Forte@Sun.COM 			}
29657836SJohn.Forte@Sun.COM 		} else {
29667836SJohn.Forte@Sun.COM 			update_queue_flags = 0;
29677836SJohn.Forte@Sun.COM 			queue_it = 0;
29687836SJohn.Forte@Sun.COM 		}
29697836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
29707836SJohn.Forte@Sun.COM 
29717836SJohn.Forte@Sun.COM 	if (update_queue_flags) {
29727836SJohn.Forte@Sun.COM 		uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE;
29737836SJohn.Forte@Sun.COM 
29747836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
29757836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] = cmd;
29767836SJohn.Forte@Sun.COM 		if (queue_it) {
29777836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
29787836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
29797836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
29807836SJohn.Forte@Sun.COM 			} else {
29817836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
29827836SJohn.Forte@Sun.COM 			}
29837836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
29847836SJohn.Forte@Sun.COM 			if (++(w->worker_queue_depth) >
29857836SJohn.Forte@Sun.COM 			    w->worker_max_qdepth_pu) {
29867836SJohn.Forte@Sun.COM 				w->worker_max_qdepth_pu = w->worker_queue_depth;
29877836SJohn.Forte@Sun.COM 			}
29887836SJohn.Forte@Sun.COM 			if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
29897836SJohn.Forte@Sun.COM 				cv_signal(&w->worker_cv);
29907836SJohn.Forte@Sun.COM 		}
29917836SJohn.Forte@Sun.COM 	}
29927836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
29937836SJohn.Forte@Sun.COM 
29947836SJohn.Forte@Sun.COM 	if (free_it) {
29957836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
29967836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
29977836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
29987836SJohn.Forte@Sun.COM 			stmf_task_free(task);
29997836SJohn.Forte@Sun.COM 		}
30007836SJohn.Forte@Sun.COM 	}
30017836SJohn.Forte@Sun.COM }
30027836SJohn.Forte@Sun.COM 
30037836SJohn.Forte@Sun.COM stmf_status_t
30047836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
30057836SJohn.Forte@Sun.COM {
30067836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
30077836SJohn.Forte@Sun.COM 		(stmf_i_scsi_task_t *)task->task_stmf_private;
30087836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
30097836SJohn.Forte@Sun.COM 		uint32_t new, old;
30107836SJohn.Forte@Sun.COM 		do {
30117836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
30127836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
30137836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
30147836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
30157836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
30167836SJohn.Forte@Sun.COM 	}
30177836SJohn.Forte@Sun.COM 
30187836SJohn.Forte@Sun.COM 	if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) {
30197836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
30207836SJohn.Forte@Sun.COM 	}
30217836SJohn.Forte@Sun.COM 
30227836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
30237836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
30247836SJohn.Forte@Sun.COM 
30257836SJohn.Forte@Sun.COM 	if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) {
30267836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
30277836SJohn.Forte@Sun.COM 		task->task_resid = 0;
30287836SJohn.Forte@Sun.COM 	} else if (task->task_cmd_xfer_length >
30297836SJohn.Forte@Sun.COM 	    task->task_expected_xfer_length) {
30307836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_OVER;
30317836SJohn.Forte@Sun.COM 		task->task_resid = task->task_cmd_xfer_length -
30327836SJohn.Forte@Sun.COM 					task->task_expected_xfer_length;
30337836SJohn.Forte@Sun.COM 	} else if (task->task_nbytes_transferred <
30347836SJohn.Forte@Sun.COM 					task->task_expected_xfer_length) {
30357836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_UNDER;
30367836SJohn.Forte@Sun.COM 		task->task_resid = task->task_expected_xfer_length -
30377836SJohn.Forte@Sun.COM 					task->task_nbytes_transferred;
30387836SJohn.Forte@Sun.COM 	} else {
30397836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
30407836SJohn.Forte@Sun.COM 		task->task_resid = 0;
30417836SJohn.Forte@Sun.COM 	}
30427836SJohn.Forte@Sun.COM 	return (task->task_lport->lport_send_status(task, ioflags));
30437836SJohn.Forte@Sun.COM }
30447836SJohn.Forte@Sun.COM 
30457836SJohn.Forte@Sun.COM void
30467836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof)
30477836SJohn.Forte@Sun.COM {
30487836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
30497836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
30507836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
30517836SJohn.Forte@Sun.COM 	uint32_t new, old;
30527836SJohn.Forte@Sun.COM 	uint8_t free_it, queue_it;
30537836SJohn.Forte@Sun.COM 
30547836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
30557836SJohn.Forte@Sun.COM 	do {
30567836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
30577836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
30587836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
30597836SJohn.Forte@Sun.COM 			return;
30607836SJohn.Forte@Sun.COM 		}
30617836SJohn.Forte@Sun.COM 		free_it = 0;
30627836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
30637836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
30647836SJohn.Forte@Sun.COM 			free_it = 1;
30657836SJohn.Forte@Sun.COM 		}
30667836SJohn.Forte@Sun.COM 		/*
30677836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
30687836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
30697836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
30707836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
30717836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
30727836SJohn.Forte@Sun.COM 		 * free this task.
30737836SJohn.Forte@Sun.COM 		 */
30747836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
30757836SJohn.Forte@Sun.COM 			free_it = 0;
30767836SJohn.Forte@Sun.COM 			queue_it = 1;
30777836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
30787836SJohn.Forte@Sun.COM 				cmn_err(CE_PANIC, "status completion received"
30797836SJohn.Forte@Sun.COM 				    " when task is already in worker queue "
30807836SJohn.Forte@Sun.COM 				    " task = %p", (void *)task);
30817836SJohn.Forte@Sun.COM 			}
30827836SJohn.Forte@Sun.COM 			new |= ITASK_IN_WORKER_QUEUE;
30837836SJohn.Forte@Sun.COM 		} else {
30847836SJohn.Forte@Sun.COM 			queue_it = 0;
30857836SJohn.Forte@Sun.COM 		}
30867836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
30877836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
30887836SJohn.Forte@Sun.COM 
30897836SJohn.Forte@Sun.COM 	if (queue_it) {
30907836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
30917836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] =
30927836SJohn.Forte@Sun.COM 		    ITASK_CMD_STATUS_DONE;
30937836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
30947836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
30957836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
30967836SJohn.Forte@Sun.COM 		} else {
30977836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
30987836SJohn.Forte@Sun.COM 		}
30997836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
31007836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
31017836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
31027836SJohn.Forte@Sun.COM 		}
31037836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
31047836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
31057836SJohn.Forte@Sun.COM 	}
31067836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
31077836SJohn.Forte@Sun.COM 
31087836SJohn.Forte@Sun.COM 	if (free_it) {
31097836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
31107836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
31117836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
31127836SJohn.Forte@Sun.COM 			stmf_task_free(task);
31137836SJohn.Forte@Sun.COM 		} else {
31147836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "LU is done with the task but LPORT "
31157836SJohn.Forte@Sun.COM 			    " is not done, itask %p", (void *)itask);
31167836SJohn.Forte@Sun.COM 		}
31177836SJohn.Forte@Sun.COM 	}
31187836SJohn.Forte@Sun.COM }
31197836SJohn.Forte@Sun.COM 
31207836SJohn.Forte@Sun.COM void
31217836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task)
31227836SJohn.Forte@Sun.COM {
31237836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
31247836SJohn.Forte@Sun.COM 		(stmf_i_scsi_task_t *)task->task_stmf_private;
31257836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
31267836SJohn.Forte@Sun.COM 	uint32_t new, old;
31277836SJohn.Forte@Sun.COM 
31287836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
31297836SJohn.Forte@Sun.COM 	do {
31307836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
31317836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
31327836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
31337836SJohn.Forte@Sun.COM 			return;
31347836SJohn.Forte@Sun.COM 		}
31357836SJohn.Forte@Sun.COM 		if (old & ITASK_IN_WORKER_QUEUE) {
31367836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "task_lu_done received"
31377836SJohn.Forte@Sun.COM 			    " when task is in worker queue "
31387836SJohn.Forte@Sun.COM 			    " task = %p", (void *)task);
31397836SJohn.Forte@Sun.COM 		}
31407836SJohn.Forte@Sun.COM 		new &= ~ITASK_KNOWN_TO_LU;
31417836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
31427836SJohn.Forte@Sun.COM 
31437836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
31447836SJohn.Forte@Sun.COM 
31457836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
31467836SJohn.Forte@Sun.COM 	    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
31477836SJohn.Forte@Sun.COM 	    ITASK_BEING_ABORTED)) == 0) {
31487836SJohn.Forte@Sun.COM 		stmf_task_free(task);
31497836SJohn.Forte@Sun.COM 	} else {
31507836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but "
31517836SJohn.Forte@Sun.COM 		    " the task is still not done, task = %p", (void *)task);
31527836SJohn.Forte@Sun.COM 	}
31537836SJohn.Forte@Sun.COM }
31547836SJohn.Forte@Sun.COM 
31557836SJohn.Forte@Sun.COM void
31567836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s)
31577836SJohn.Forte@Sun.COM {
31587836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
31597836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
31607836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
31617836SJohn.Forte@Sun.COM 	uint32_t old, new;
31627836SJohn.Forte@Sun.COM 
31637836SJohn.Forte@Sun.COM 	do {
31647836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
31657836SJohn.Forte@Sun.COM 		if ((old & ITASK_BEING_ABORTED) ||
31667836SJohn.Forte@Sun.COM 		    ((old & (ITASK_KNOWN_TO_TGT_PORT |
31677836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU)) == 0)) {
31687836SJohn.Forte@Sun.COM 			return;
31697836SJohn.Forte@Sun.COM 		}
31707836SJohn.Forte@Sun.COM 		new |= ITASK_BEING_ABORTED;
31717836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
31727836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
31737836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
31747836SJohn.Forte@Sun.COM 
31757836SJohn.Forte@Sun.COM 	if (((w = itask->itask_worker) == NULL) ||
31767836SJohn.Forte@Sun.COM 	    (itask->itask_flags & ITASK_IN_TRANSITION)) {
31777836SJohn.Forte@Sun.COM 		return;
31787836SJohn.Forte@Sun.COM 	}
31797836SJohn.Forte@Sun.COM 
31807836SJohn.Forte@Sun.COM 	/* Queue it and get out */
31817836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
31827836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) {
31837836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
31847836SJohn.Forte@Sun.COM 		return;
31857836SJohn.Forte@Sun.COM 	}
31867836SJohn.Forte@Sun.COM 	atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
31877836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
31887836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
31897836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
31907836SJohn.Forte@Sun.COM 	} else {
31917836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
31927836SJohn.Forte@Sun.COM 	}
31937836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
31947836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
31957836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
31967836SJohn.Forte@Sun.COM 	}
31977836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
31987836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
31997836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
32007836SJohn.Forte@Sun.COM }
32017836SJohn.Forte@Sun.COM 
32027836SJohn.Forte@Sun.COM void
32037836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg)
32047836SJohn.Forte@Sun.COM {
32057836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = NULL;
32067836SJohn.Forte@Sun.COM 	uint32_t old, new, f, rf;
32077836SJohn.Forte@Sun.COM 
32087836SJohn.Forte@Sun.COM 	switch (abort_cmd) {
32097836SJohn.Forte@Sun.COM 	case STMF_QUEUE_ABORT_LU:
32107836SJohn.Forte@Sun.COM 		stmf_task_lu_killall((stmf_lu_t *)arg, task, s);
32117836SJohn.Forte@Sun.COM 		return;
32127836SJohn.Forte@Sun.COM 	case STMF_QUEUE_TASK_ABORT:
32137836SJohn.Forte@Sun.COM 		stmf_queue_task_for_abort(task, s);
32147836SJohn.Forte@Sun.COM 		return;
32157836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LPORT:
32167836SJohn.Forte@Sun.COM 		rf = ITASK_TGT_PORT_ABORT_CALLED;
32177836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_TGT_PORT;
32187836SJohn.Forte@Sun.COM 		break;
32197836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LU:
32207836SJohn.Forte@Sun.COM 		rf = ITASK_LU_ABORT_CALLED;
32217836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_LU;
32227836SJohn.Forte@Sun.COM 		break;
32237836SJohn.Forte@Sun.COM 	default:
32247836SJohn.Forte@Sun.COM 		return;
32257836SJohn.Forte@Sun.COM 	}
32267836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
32277836SJohn.Forte@Sun.COM 	f |= ITASK_BEING_ABORTED | rf;
32287836SJohn.Forte@Sun.COM 	do {
32297836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
32307836SJohn.Forte@Sun.COM 		if ((old & f) != f) {
32317836SJohn.Forte@Sun.COM 			return;
32327836SJohn.Forte@Sun.COM 		}
32337836SJohn.Forte@Sun.COM 		new &= ~rf;
32347836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
32357836SJohn.Forte@Sun.COM }
32367836SJohn.Forte@Sun.COM 
32377836SJohn.Forte@Sun.COM void
32387836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
32397836SJohn.Forte@Sun.COM {
32407836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
32417836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
32427836SJohn.Forte@Sun.COM 	unsigned long long	st;
32437836SJohn.Forte@Sun.COM 
32447836SJohn.Forte@Sun.COM 	st = s;	/* gcc fix */
32457836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
32467836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
32477836SJohn.Forte@Sun.COM 		    "task %p, lu failed to abort ret=%llx", (void *)task, st);
32487836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LU_DONE) == 0) {
32497836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
32507836SJohn.Forte@Sun.COM 		    "Task aborted but LU is not finished, task ="
32517836SJohn.Forte@Sun.COM 		    "%p, s=%llx, iof=%x", (void *)task, st, iof);
32527836SJohn.Forte@Sun.COM 	} else {
32537836SJohn.Forte@Sun.COM 		/*
32547836SJohn.Forte@Sun.COM 		 * LU abort successfully
32557836SJohn.Forte@Sun.COM 		 */
32567836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU);
32577836SJohn.Forte@Sun.COM 		return;
32587836SJohn.Forte@Sun.COM 	}
32597836SJohn.Forte@Sun.COM 
32607836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
32617836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 1, info);
32627836SJohn.Forte@Sun.COM }
32637836SJohn.Forte@Sun.COM 
32647836SJohn.Forte@Sun.COM void
32657836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
32667836SJohn.Forte@Sun.COM {
32677836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
32687836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
32697836SJohn.Forte@Sun.COM 	unsigned long long	st;
32707836SJohn.Forte@Sun.COM 
32717836SJohn.Forte@Sun.COM 	st = s;
32727836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
32737836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
32747836SJohn.Forte@Sun.COM 		    "task %p, tgt port failed to abort ret=%llx", (void *)task,
32757836SJohn.Forte@Sun.COM 		    st);
32767836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LPORT_DONE) == 0) {
32777836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
32787836SJohn.Forte@Sun.COM 		    "Task aborted but tgt port is not finished, "
32797836SJohn.Forte@Sun.COM 		    "task=%p, s=%llx, iof=%x", (void *)task, st, iof);
32807836SJohn.Forte@Sun.COM 	} else {
32817836SJohn.Forte@Sun.COM 		/*
32827836SJohn.Forte@Sun.COM 		 * LU abort successfully
32837836SJohn.Forte@Sun.COM 		 */
32847836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT);
32857836SJohn.Forte@Sun.COM 		return;
32867836SJohn.Forte@Sun.COM 	}
32877836SJohn.Forte@Sun.COM 
32887836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
32897836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 0, info);
32907836SJohn.Forte@Sun.COM }
32917836SJohn.Forte@Sun.COM 
32927836SJohn.Forte@Sun.COM stmf_status_t
32937836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout)
32947836SJohn.Forte@Sun.COM {
32957836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
32967836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
32977836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
32987836SJohn.Forte@Sun.COM 	int i;
32997836SJohn.Forte@Sun.COM 
33007836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU);
33017836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
33027836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
33037836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
33047836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
33057836SJohn.Forte@Sun.COM 	}
33067836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
33077836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) {
33087836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
33097836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
33107836SJohn.Forte@Sun.COM 		}
33117836SJohn.Forte@Sun.COM 	}
33127836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU;
33137836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
33147836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
33157836SJohn.Forte@Sun.COM 	} else {
33167836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
33177836SJohn.Forte@Sun.COM 		if (t == 0)
33187836SJohn.Forte@Sun.COM 			t = 1;
33197836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
33207836SJohn.Forte@Sun.COM 	}
33217836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
33227836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
33237836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
33247836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
33257836SJohn.Forte@Sun.COM 		} else {
33267836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
33277836SJohn.Forte@Sun.COM 		}
33287836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
33297836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
33307836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
33317836SJohn.Forte@Sun.COM 		}
33327836SJohn.Forte@Sun.COM 		atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
33337836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
33347836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
33357836SJohn.Forte@Sun.COM 	}
33367836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
33377836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
33387836SJohn.Forte@Sun.COM }
33397836SJohn.Forte@Sun.COM 
33407836SJohn.Forte@Sun.COM stmf_status_t
33417836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout)
33427836SJohn.Forte@Sun.COM {
33437836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
33447836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
33457836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
33467836SJohn.Forte@Sun.COM 	int i;
33477836SJohn.Forte@Sun.COM 
33487836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT);
33497836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
33507836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
33517836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
33527836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
33537836SJohn.Forte@Sun.COM 	}
33547836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
33557836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) {
33567836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
33577836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
33587836SJohn.Forte@Sun.COM 		}
33597836SJohn.Forte@Sun.COM 	}
33607836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT;
33617836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
33627836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
33637836SJohn.Forte@Sun.COM 	} else {
33647836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
33657836SJohn.Forte@Sun.COM 		if (t == 0)
33667836SJohn.Forte@Sun.COM 			t = 1;
33677836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
33687836SJohn.Forte@Sun.COM 	}
33697836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
33707836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
33717836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
33727836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
33737836SJohn.Forte@Sun.COM 		} else {
33747836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
33757836SJohn.Forte@Sun.COM 		}
33767836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
33777836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
33787836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
33797836SJohn.Forte@Sun.COM 		}
33807836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
33817836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
33827836SJohn.Forte@Sun.COM 	}
33837836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
33847836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
33857836SJohn.Forte@Sun.COM }
33867836SJohn.Forte@Sun.COM 
33877836SJohn.Forte@Sun.COM void
33887836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task)
33897836SJohn.Forte@Sun.COM {
33907836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
33917836SJohn.Forte@Sun.COM 	stmf_lu_t		*lu;
33927836SJohn.Forte@Sun.COM 	stmf_local_port_t	*lport;
33937836SJohn.Forte@Sun.COM 	unsigned long long	 ret;
33947836SJohn.Forte@Sun.COM 	uint32_t		 old, new;
33957836SJohn.Forte@Sun.COM 	uint8_t			 call_lu_abort, call_port_abort;
33967836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
33977836SJohn.Forte@Sun.COM 
33987836SJohn.Forte@Sun.COM 	lu = task->task_lu;
33997836SJohn.Forte@Sun.COM 	lport = task->task_lport;
34007836SJohn.Forte@Sun.COM 	do {
34017836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
34027836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) ==
34037836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU) {
34047836SJohn.Forte@Sun.COM 			new |= ITASK_LU_ABORT_CALLED;
34057836SJohn.Forte@Sun.COM 			call_lu_abort = 1;
34067836SJohn.Forte@Sun.COM 		} else {
34077836SJohn.Forte@Sun.COM 			call_lu_abort = 0;
34087836SJohn.Forte@Sun.COM 		}
34097836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34107836SJohn.Forte@Sun.COM 
34117836SJohn.Forte@Sun.COM 	if (call_lu_abort) {
34127836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) {
34137836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
34147836SJohn.Forte@Sun.COM 		} else {
34157836SJohn.Forte@Sun.COM 			ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
34167836SJohn.Forte@Sun.COM 		}
34177836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
34187836SJohn.Forte@Sun.COM 			stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE);
34197836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
34207836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
34217836SJohn.Forte@Sun.COM 			    ~ITASK_LU_ABORT_CALLED);
34227836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
34237836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
34247836SJohn.Forte@Sun.COM 			    "Abort failed by LU %p, ret %llx", (void *)lu, ret);
34257836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
34267836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 1, info);
34277836SJohn.Forte@Sun.COM 		}
34287836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_LU) {
34297836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
34307836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lu->lu_abort_timeout?
34317836SJohn.Forte@Sun.COM 		    lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) {
34327836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
34337836SJohn.Forte@Sun.COM 			    "lu abort timed out");
34347836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
34357836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 1, info);
34367836SJohn.Forte@Sun.COM 		}
34377836SJohn.Forte@Sun.COM 	}
34387836SJohn.Forte@Sun.COM 
34397836SJohn.Forte@Sun.COM 	do {
34407836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
34417836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_TGT_PORT |
34427836SJohn.Forte@Sun.COM 		    ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) {
34437836SJohn.Forte@Sun.COM 			new |= ITASK_TGT_PORT_ABORT_CALLED;
34447836SJohn.Forte@Sun.COM 			call_port_abort = 1;
34457836SJohn.Forte@Sun.COM 		} else {
34467836SJohn.Forte@Sun.COM 			call_port_abort = 0;
34477836SJohn.Forte@Sun.COM 		}
34487836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34497836SJohn.Forte@Sun.COM 	if (call_port_abort) {
34507836SJohn.Forte@Sun.COM 		ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK,
34517836SJohn.Forte@Sun.COM 								task, 0);
34527836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
34537836SJohn.Forte@Sun.COM 			stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE);
34547836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
34557836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
34567836SJohn.Forte@Sun.COM 			    ~ITASK_TGT_PORT_ABORT_CALLED);
34577836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
34587836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
34597836SJohn.Forte@Sun.COM 			    "Abort failed by tgt port %p ret %llx",
34607836SJohn.Forte@Sun.COM 			    (void *)lport, ret);
34617836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
34627836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 0, info);
34637836SJohn.Forte@Sun.COM 		}
34647836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) {
34657836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
34667836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lport->lport_abort_timeout?
34677836SJohn.Forte@Sun.COM 		    lport->lport_abort_timeout :
34687836SJohn.Forte@Sun.COM 		    ITASK_DEFAULT_ABORT_TIMEOUT))) {
34697836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
34707836SJohn.Forte@Sun.COM 			    "lport abort timed out");
34717836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
34727836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 0, info);
34737836SJohn.Forte@Sun.COM 		}
34747836SJohn.Forte@Sun.COM 	}
34757836SJohn.Forte@Sun.COM }
34767836SJohn.Forte@Sun.COM 
34777836SJohn.Forte@Sun.COM stmf_status_t
34787836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg)
34797836SJohn.Forte@Sun.COM {
34807836SJohn.Forte@Sun.COM 	stmf_status_t			ret;
34817836SJohn.Forte@Sun.COM 	stmf_i_lu_t			*ilu;
34827836SJohn.Forte@Sun.COM 	stmf_i_local_port_t		*ilport;
34837836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
34847836SJohn.Forte@Sun.COM 
34857836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
34867836SJohn.Forte@Sun.COM 	ret = STMF_INVALID_ARG;
34877836SJohn.Forte@Sun.COM 	if (cmd & STMF_CMD_LU_OP) {
34887836SJohn.Forte@Sun.COM 		ilu = stmf_lookup_lu((stmf_lu_t *)obj);
34897836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
34907836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
34917836SJohn.Forte@Sun.COM 		}
34927836SJohn.Forte@Sun.COM 	} else if (cmd & STMF_CMD_LPORT_OP) {
34937836SJohn.Forte@Sun.COM 		ilport = stmf_lookup_lport((stmf_local_port_t *)obj);
34947836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
34957836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
34967836SJohn.Forte@Sun.COM 		}
34977836SJohn.Forte@Sun.COM 	} else {
34987836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
34997836SJohn.Forte@Sun.COM 	}
35007836SJohn.Forte@Sun.COM 
35017836SJohn.Forte@Sun.COM 	switch (cmd) {
35027836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE:
35037836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_ONLINE) {
35047836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
35057836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35067836SJohn.Forte@Sun.COM 		}
35077836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINE) {
35087836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
35097836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35107836SJohn.Forte@Sun.COM 		}
35117836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_ONLINING;
35127836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
35137836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
35147836SJohn.Forte@Sun.COM 		break;
35157836SJohn.Forte@Sun.COM 
35167836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE_COMPLETE:
35177836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINING) {
35187836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
35197836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35207836SJohn.Forte@Sun.COM 		}
35217836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
35227836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
35237836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
35247836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
35257836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
35267836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_ONLINE_COMPLETE, arg);
35277836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
35287836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
35297836SJohn.Forte@Sun.COM 		} else {
35307836SJohn.Forte@Sun.COM 			/* XXX: should throw a meesage an record more data */
35317836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
35327836SJohn.Forte@Sun.COM 		}
35337836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
35347836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
35357836SJohn.Forte@Sun.COM 
35367836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE:
35377836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE) {
35387836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
35397836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35407836SJohn.Forte@Sun.COM 		}
35417836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE) {
35427836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
35437836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35447836SJohn.Forte@Sun.COM 		}
35457836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_OFFLINING;
35467836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
35477836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
35487836SJohn.Forte@Sun.COM 		break;
35497836SJohn.Forte@Sun.COM 
35507836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE_COMPLETE:
35517836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINING) {
35527836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
35537836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35547836SJohn.Forte@Sun.COM 		}
35557836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
35567836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
35577836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
35587836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
35597836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
35607836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_OFFLINE_COMPLETE, arg);
35617836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
35627836SJohn.Forte@Sun.COM 		} else {
35637836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
35647836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
35657836SJohn.Forte@Sun.COM 		}
35667836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
35677836SJohn.Forte@Sun.COM 		break;
35687836SJohn.Forte@Sun.COM 
35697836SJohn.Forte@Sun.COM 	/*
35707836SJohn.Forte@Sun.COM 	 * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online.
35717836SJohn.Forte@Sun.COM 	 * It's related with hardware disable/enable.
35727836SJohn.Forte@Sun.COM 	 */
35737836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE:
35747836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_ONLINE) {
35757836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
35767836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35777836SJohn.Forte@Sun.COM 		}
35787836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINE) {
35797836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
35807836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
35817836SJohn.Forte@Sun.COM 		}
35827836SJohn.Forte@Sun.COM 
35837836SJohn.Forte@Sun.COM 		/*
35847836SJohn.Forte@Sun.COM 		 * Only user request can recover the port from the
35857836SJohn.Forte@Sun.COM 		 * FORCED_OFFLINE state
35867836SJohn.Forte@Sun.COM 		 */
35877836SJohn.Forte@Sun.COM 		if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) {
35887836SJohn.Forte@Sun.COM 			if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) {
35897836SJohn.Forte@Sun.COM 				ret = STMF_FAILURE;
35907836SJohn.Forte@Sun.COM 				goto stmf_ctl_lock_exit;
35917836SJohn.Forte@Sun.COM 			}
35927836SJohn.Forte@Sun.COM 		}
35937836SJohn.Forte@Sun.COM 
35947836SJohn.Forte@Sun.COM 		/*
35957836SJohn.Forte@Sun.COM 		 * Avoid too frequent request to online
35967836SJohn.Forte@Sun.COM 		 */
35977836SJohn.Forte@Sun.COM 		if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
35987836SJohn.Forte@Sun.COM 			ilport->ilport_online_times = 0;
35997836SJohn.Forte@Sun.COM 			ilport->ilport_avg_interval = 0;
36007836SJohn.Forte@Sun.COM 		}
36017836SJohn.Forte@Sun.COM 		if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) &&
36027836SJohn.Forte@Sun.COM 		    (ilport->ilport_online_times >= 4)) {
36037836SJohn.Forte@Sun.COM 			ret = STMF_FAILURE;
36047836SJohn.Forte@Sun.COM 			ilport->ilport_flags |= ILPORT_FORCED_OFFLINE;
36057836SJohn.Forte@Sun.COM 			stmf_trace(NULL, "stmf_ctl: too frequent request to "
36067836SJohn.Forte@Sun.COM 			    "online the port");
36077836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "stmf_ctl: too frequent request to "
36087836SJohn.Forte@Sun.COM 			    "online the port, set FORCED_OFFLINE now");
36097836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
36107836SJohn.Forte@Sun.COM 		}
36117836SJohn.Forte@Sun.COM 		if (ilport->ilport_online_times > 0) {
36127836SJohn.Forte@Sun.COM 			if (ilport->ilport_online_times == 1) {
36137836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval = ddi_get_lbolt() -
36147836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock;
36157836SJohn.Forte@Sun.COM 			} else {
36167836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval =
36177836SJohn.Forte@Sun.COM 				    (ilport->ilport_avg_interval +
36187836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() -
36197836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock) >> 1;
36207836SJohn.Forte@Sun.COM 			}
36217836SJohn.Forte@Sun.COM 		}
36227836SJohn.Forte@Sun.COM 		ilport->ilport_last_online_clock = ddi_get_lbolt();
36237836SJohn.Forte@Sun.COM 		ilport->ilport_online_times++;
36247836SJohn.Forte@Sun.COM 
36257836SJohn.Forte@Sun.COM 		/*
36267836SJohn.Forte@Sun.COM 		 * Submit online service request
36277836SJohn.Forte@Sun.COM 		 */
36287836SJohn.Forte@Sun.COM 		ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE;
36297836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_ONLINING;
36307836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
36317836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
36327836SJohn.Forte@Sun.COM 		break;
36337836SJohn.Forte@Sun.COM 
36347836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE_COMPLETE:
36357836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINING) {
36367836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
36377836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
36387836SJohn.Forte@Sun.COM 		}
36397836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
36407836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
36417836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
36427836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
36437836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
36447836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
36457836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_ONLINE_COMPLETE, arg);
36467836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
36477836SJohn.Forte@Sun.COM 		} else {
36487836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
36497836SJohn.Forte@Sun.COM 		}
36507836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
36517836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
36527836SJohn.Forte@Sun.COM 
36537836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE:
36547836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE) {
36557836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
36567836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
36577836SJohn.Forte@Sun.COM 		}
36587836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE) {
36597836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
36607836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
36617836SJohn.Forte@Sun.COM 		}
36627836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_OFFLINING;
36637836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
36647836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
36657836SJohn.Forte@Sun.COM 		break;
36667836SJohn.Forte@Sun.COM 
36677836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE_COMPLETE:
36687836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
36697836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
36707836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
36717836SJohn.Forte@Sun.COM 		}
36727836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
36737836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
36747836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
36757836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
36767836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
36777836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
36787836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_OFFLINE_COMPLETE, arg);
36797836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
36807836SJohn.Forte@Sun.COM 		} else {
36817836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
36827836SJohn.Forte@Sun.COM 		}
36837836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
36847836SJohn.Forte@Sun.COM 		break;
36857836SJohn.Forte@Sun.COM 
36867836SJohn.Forte@Sun.COM 	default:
36877836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd);
36887836SJohn.Forte@Sun.COM 		ret = STMF_INVALID_ARG;
36897836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
36907836SJohn.Forte@Sun.COM 	}
36917836SJohn.Forte@Sun.COM 
36927836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
36937836SJohn.Forte@Sun.COM 
36947836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:;
36957836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
36967836SJohn.Forte@Sun.COM 	return (ret);
36977836SJohn.Forte@Sun.COM }
36987836SJohn.Forte@Sun.COM 
36997836SJohn.Forte@Sun.COM /* ARGSUSED */
37007836SJohn.Forte@Sun.COM stmf_status_t
37017836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
37027836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
37037836SJohn.Forte@Sun.COM {
37047836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
37057836SJohn.Forte@Sun.COM }
37067836SJohn.Forte@Sun.COM 
37077836SJohn.Forte@Sun.COM /* ARGSUSED */
37087836SJohn.Forte@Sun.COM stmf_status_t
37097836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
37107836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
37117836SJohn.Forte@Sun.COM {
37127836SJohn.Forte@Sun.COM 	uint32_t cl = SI_GET_CLASS(cmd);
37137836SJohn.Forte@Sun.COM 
37147836SJohn.Forte@Sun.COM 	if (cl == SI_STMF) {
37157836SJohn.Forte@Sun.COM 		return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep));
37167836SJohn.Forte@Sun.COM 	}
37177836SJohn.Forte@Sun.COM 	if (cl == SI_LPORT) {
37187836SJohn.Forte@Sun.COM 		return (((stmf_local_port_t *)arg1)->lport_info(cmd,
37197836SJohn.Forte@Sun.COM 				arg1, arg2, buf, bufsizep));
37207836SJohn.Forte@Sun.COM 	} else if (cl == SI_LU) {
37217836SJohn.Forte@Sun.COM 		return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2,
37227836SJohn.Forte@Sun.COM 						buf, bufsizep));
37237836SJohn.Forte@Sun.COM 	}
37247836SJohn.Forte@Sun.COM 
37257836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
37267836SJohn.Forte@Sun.COM }
37277836SJohn.Forte@Sun.COM 
37287836SJohn.Forte@Sun.COM /*
37297836SJohn.Forte@Sun.COM  * Used by port providers. pwwn is 8 byte wwn, sdid is th devid used by
37307836SJohn.Forte@Sun.COM  * stmf to register local ports. The ident should have 20 bytes in buffer
37317836SJohn.Forte@Sun.COM  * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string.
37327836SJohn.Forte@Sun.COM  */
37337836SJohn.Forte@Sun.COM void
37347836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn,
37357836SJohn.Forte@Sun.COM     uint8_t protocol_id)
37367836SJohn.Forte@Sun.COM {
37377836SJohn.Forte@Sun.COM 	sdid->protocol_id = protocol_id;
37387836SJohn.Forte@Sun.COM 	sdid->piv = 1;
37397836SJohn.Forte@Sun.COM 	sdid->code_set = CODE_SET_ASCII;
37407836SJohn.Forte@Sun.COM 	sdid->association = ID_IS_TARGET_PORT;
37417836SJohn.Forte@Sun.COM 	sdid->ident_length = 20;
37427836SJohn.Forte@Sun.COM 	(void) sprintf((char *)sdid->ident,
37437836SJohn.Forte@Sun.COM 	    "wwn.%02X%02X%02X%02X%02X%02X%02X%02X",
37447836SJohn.Forte@Sun.COM 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
37457836SJohn.Forte@Sun.COM }
37467836SJohn.Forte@Sun.COM 
37477836SJohn.Forte@Sun.COM stmf_xfer_data_t *
37487836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data()
37497836SJohn.Forte@Sun.COM {
37507836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
37517836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
37527836SJohn.Forte@Sun.COM 	uint8_t *p;
37537836SJohn.Forte@Sun.COM 	uint32_t sz, asz, nports;
37547836SJohn.Forte@Sun.COM 
37557836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
37567836SJohn.Forte@Sun.COM 	/* The spec only allows for 255 ports to be reported */
37577836SJohn.Forte@Sun.COM 	nports = min(stmf_state.stmf_nlports, 255);
37587836SJohn.Forte@Sun.COM 	sz = (nports * 4) + 12;
37597836SJohn.Forte@Sun.COM 	asz = sz + sizeof (*xd) - 4;
37607836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
37617836SJohn.Forte@Sun.COM 	if (xd == NULL) {
37627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
37637836SJohn.Forte@Sun.COM 		return (NULL);
37647836SJohn.Forte@Sun.COM 	}
37657836SJohn.Forte@Sun.COM 	xd->alloc_size = asz;
37667836SJohn.Forte@Sun.COM 	xd->size_left = sz;
37677836SJohn.Forte@Sun.COM 
37687836SJohn.Forte@Sun.COM 	p = xd->buf;
37697836SJohn.Forte@Sun.COM 
37707836SJohn.Forte@Sun.COM 	*((uint32_t *)p) = BE_32(sz - 4);
37717836SJohn.Forte@Sun.COM 	p += 4;
37727836SJohn.Forte@Sun.COM 	p[0] = 0x80;	/* PREF */
37737836SJohn.Forte@Sun.COM 	p[1] = 1;	/* AO_SUP */
37747836SJohn.Forte@Sun.COM 	p[7] = nports & 0xff;
37757836SJohn.Forte@Sun.COM 	p += 8;
37767836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport && nports;
37777836SJohn.Forte@Sun.COM 	    nports++, ilport = ilport->ilport_next, p += 4) {
37787836SJohn.Forte@Sun.COM 		((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid);
37797836SJohn.Forte@Sun.COM 	}
37807836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
37817836SJohn.Forte@Sun.COM 
37827836SJohn.Forte@Sun.COM 	return (xd);
37837836SJohn.Forte@Sun.COM }
37847836SJohn.Forte@Sun.COM 
37857836SJohn.Forte@Sun.COM 
37867836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0;
37877836SJohn.Forte@Sun.COM extern char hw_serial[];
37887836SJohn.Forte@Sun.COM 
37897836SJohn.Forte@Sun.COM stmf_status_t
37907836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id)
37917836SJohn.Forte@Sun.COM {
37927836SJohn.Forte@Sun.COM 	uint8_t *p;
37937836SJohn.Forte@Sun.COM 	struct timeval32 timestamp32;
37947836SJohn.Forte@Sun.COM 	uint32_t *t = (uint32_t *)&timestamp32;
37957836SJohn.Forte@Sun.COM 	struct ether_addr mac;
37967836SJohn.Forte@Sun.COM 	uint8_t *e = (uint8_t *)&mac;
37977836SJohn.Forte@Sun.COM 
37987836SJohn.Forte@Sun.COM 	if (company_id == COMPANY_ID_NONE)
37997836SJohn.Forte@Sun.COM 		company_id = COMPANY_ID_SUN;
38007836SJohn.Forte@Sun.COM 
38017836SJohn.Forte@Sun.COM 	if (lu_id->ident_length != 0x10)
38027836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
38037836SJohn.Forte@Sun.COM 
38047836SJohn.Forte@Sun.COM 	p = (uint8_t *)lu_id;
38057836SJohn.Forte@Sun.COM 
38067836SJohn.Forte@Sun.COM 	atomic_add_16(&stmf_lu_id_gen_number, 1);
38077836SJohn.Forte@Sun.COM 
38087836SJohn.Forte@Sun.COM 	p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
38097836SJohn.Forte@Sun.COM 	p[4] = ((company_id >> 20) & 0xf) | 0x60;
38107836SJohn.Forte@Sun.COM 	p[5] = (company_id >> 12) & 0xff;
38117836SJohn.Forte@Sun.COM 	p[6] = (company_id >> 4) & 0xff;
38127836SJohn.Forte@Sun.COM 	p[7] = (company_id << 4) & 0xf0;
38137836SJohn.Forte@Sun.COM 	if (!localetheraddr((struct ether_addr *)NULL, &mac)) {
38147836SJohn.Forte@Sun.COM 		char *hp = &hw_serial[0];
38157836SJohn.Forte@Sun.COM 		int hid = BE_32(stoi(&hp));
38167836SJohn.Forte@Sun.COM 
38177836SJohn.Forte@Sun.COM 		e[0] = (hid >> 24) & 0xff;
38187836SJohn.Forte@Sun.COM 		e[1] = (hid >> 16) & 0xff;
38197836SJohn.Forte@Sun.COM 		e[2] = (hid >> 8) & 0xff;
38207836SJohn.Forte@Sun.COM 		e[3] = hid & 0xff;
38217836SJohn.Forte@Sun.COM 		e[4] = e[5] = 0;
38227836SJohn.Forte@Sun.COM 	}
38237836SJohn.Forte@Sun.COM 	bcopy(e, p+8, 6);
38247836SJohn.Forte@Sun.COM 	uniqtime32(&timestamp32);
38257836SJohn.Forte@Sun.COM 	*t = BE_32(*t);
38267836SJohn.Forte@Sun.COM 	bcopy(t, p+14, 4);
38277836SJohn.Forte@Sun.COM 	p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
38287836SJohn.Forte@Sun.COM 	p[19] = stmf_lu_id_gen_number & 0xff;
38297836SJohn.Forte@Sun.COM 
38307836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
38317836SJohn.Forte@Sun.COM }
38327836SJohn.Forte@Sun.COM 
38337836SJohn.Forte@Sun.COM /*
38347836SJohn.Forte@Sun.COM  * saa is sense key, ASC, ASCQ
38357836SJohn.Forte@Sun.COM  */
38367836SJohn.Forte@Sun.COM void
38377836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa)
38387836SJohn.Forte@Sun.COM {
38397836SJohn.Forte@Sun.COM 	uint8_t sd[18];
38407836SJohn.Forte@Sun.COM 	task->task_scsi_status = st;
38417836SJohn.Forte@Sun.COM 	if (st == 2) {
38427836SJohn.Forte@Sun.COM 		bzero(sd, 18);
38437836SJohn.Forte@Sun.COM 		sd[0] = 0x70;
38447836SJohn.Forte@Sun.COM 		sd[2] = (saa >> 16) & 0xf;
38457836SJohn.Forte@Sun.COM 		sd[7] = 10;
38467836SJohn.Forte@Sun.COM 		sd[12] = (saa >> 8) & 0xff;
38477836SJohn.Forte@Sun.COM 		sd[13] = saa & 0xff;
38487836SJohn.Forte@Sun.COM 		task->task_sense_data = sd;
38497836SJohn.Forte@Sun.COM 		task->task_sense_length = 18;
38507836SJohn.Forte@Sun.COM 	} else {
38517836SJohn.Forte@Sun.COM 		task->task_sense_data = NULL;
38527836SJohn.Forte@Sun.COM 		task->task_sense_length = 0;
38537836SJohn.Forte@Sun.COM 	}
38547836SJohn.Forte@Sun.COM 	(void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
38557836SJohn.Forte@Sun.COM }
38567836SJohn.Forte@Sun.COM 
38577836SJohn.Forte@Sun.COM uint32_t
38587836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page,
38597836SJohn.Forte@Sun.COM     uint32_t page_len, uint8_t byte0, uint32_t vpd_mask)
38607836SJohn.Forte@Sun.COM {
38617836SJohn.Forte@Sun.COM 	uint8_t		*p = NULL;
38627836SJohn.Forte@Sun.COM 	uint8_t		small_buf[32];
38637836SJohn.Forte@Sun.COM 	uint32_t	sz = 0;
38647836SJohn.Forte@Sun.COM 	uint32_t	n = 4;
38657836SJohn.Forte@Sun.COM 	uint32_t	m = 0;
38667836SJohn.Forte@Sun.COM 	uint32_t	last_bit = 0;
38677836SJohn.Forte@Sun.COM 
38687836SJohn.Forte@Sun.COM 	if (page_len < 4)
38697836SJohn.Forte@Sun.COM 		return (0);
38707836SJohn.Forte@Sun.COM 	if (page_len > 65535)
38717836SJohn.Forte@Sun.COM 		page_len = 65535;
38727836SJohn.Forte@Sun.COM 
38737836SJohn.Forte@Sun.COM 	page[0] = byte0;
38747836SJohn.Forte@Sun.COM 	page[1] = 0x83;
38757836SJohn.Forte@Sun.COM 
38767836SJohn.Forte@Sun.COM 	/* CONSTCOND */
38777836SJohn.Forte@Sun.COM 	while (1) {
38787836SJohn.Forte@Sun.COM 		m += sz;
38797836SJohn.Forte@Sun.COM 		if (sz && (page_len > n)) {
38807836SJohn.Forte@Sun.COM 			uint32_t copysz;
38817836SJohn.Forte@Sun.COM 			copysz = page_len > (n + sz) ? sz : page_len - n;
38827836SJohn.Forte@Sun.COM 			bcopy(p, page + n, copysz);
38837836SJohn.Forte@Sun.COM 			n += copysz;
38847836SJohn.Forte@Sun.COM 		}
38857836SJohn.Forte@Sun.COM 		vpd_mask &= ~last_bit;
38867836SJohn.Forte@Sun.COM 		if (vpd_mask == 0)
38877836SJohn.Forte@Sun.COM 			break;
38887836SJohn.Forte@Sun.COM 
38897836SJohn.Forte@Sun.COM 		if (vpd_mask & STMF_VPD_LU_ID) {
38907836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_LU_ID;
38917836SJohn.Forte@Sun.COM 			sz = task->task_lu->lu_id->ident_length + 4;
38927836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lu->lu_id;
38937836SJohn.Forte@Sun.COM 			continue;
38947836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TARGET_ID) {
38957836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TARGET_ID;
38967836SJohn.Forte@Sun.COM 			sz = task->task_lport->lport_id->ident_length + 4;
38977836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lport->lport_id;
38987836SJohn.Forte@Sun.COM 			continue;
38997836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TP_GROUP) {
39007836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TP_GROUP;
39017836SJohn.Forte@Sun.COM 			p = small_buf;
39027836SJohn.Forte@Sun.COM 			bzero(p, 8);
39037836SJohn.Forte@Sun.COM 			p[0] = 1;
39047836SJohn.Forte@Sun.COM 			p[1] = 0x15;
39057836SJohn.Forte@Sun.COM 			p[3] = 4;
39067836SJohn.Forte@Sun.COM 			/* Group ID is always 0 */
39077836SJohn.Forte@Sun.COM 			sz = 8;
39087836SJohn.Forte@Sun.COM 			continue;
39097836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) {
39107836SJohn.Forte@Sun.COM 			stmf_i_local_port_t *ilport;
39117836SJohn.Forte@Sun.COM 
39127836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_RELATIVE_TP_ID;
39137836SJohn.Forte@Sun.COM 			p = small_buf;
39147836SJohn.Forte@Sun.COM 			bzero(p, 8);
39157836SJohn.Forte@Sun.COM 			p[0] = 1;
39167836SJohn.Forte@Sun.COM 			p[1] = 0x14;
39177836SJohn.Forte@Sun.COM 			p[3] = 4;
39187836SJohn.Forte@Sun.COM 			ilport = (stmf_i_local_port_t *)
39197836SJohn.Forte@Sun.COM 					task->task_lport->lport_stmf_private;
39207836SJohn.Forte@Sun.COM 			p[6] = (ilport->ilport_rtpid >> 8) & 0xff;
39217836SJohn.Forte@Sun.COM 			p[7] = ilport->ilport_rtpid & 0xff;
39227836SJohn.Forte@Sun.COM 			sz = 8;
39237836SJohn.Forte@Sun.COM 			continue;
39247836SJohn.Forte@Sun.COM 		} else {
39257836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "Invalid vpd_mask");
39267836SJohn.Forte@Sun.COM 			break;
39277836SJohn.Forte@Sun.COM 		}
39287836SJohn.Forte@Sun.COM 	}
39297836SJohn.Forte@Sun.COM 
39307836SJohn.Forte@Sun.COM 	page[2] = (m >> 8) & 0xff;
39317836SJohn.Forte@Sun.COM 	page[3] = m & 0xff;
39327836SJohn.Forte@Sun.COM 
39337836SJohn.Forte@Sun.COM 	return (n);
39347836SJohn.Forte@Sun.COM }
39357836SJohn.Forte@Sun.COM 
39367836SJohn.Forte@Sun.COM void
39377836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf)
39387836SJohn.Forte@Sun.COM {
39397836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
39407836SJohn.Forte@Sun.COM 			(stmf_i_scsi_task_t *)task->task_stmf_private;
39417836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
39427836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
39437836SJohn.Forte@Sun.COM 
39447836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING;
39457836SJohn.Forte@Sun.COM 	task->task_cmd_xfer_length =
39467836SJohn.Forte@Sun.COM 	    ((((uint32_t)task->task_cdb[6]) << 24) |
39477836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[7]) << 16) |
39487836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[8]) << 8) |
39497836SJohn.Forte@Sun.COM 	    ((uint32_t)task->task_cdb[9]));
39507836SJohn.Forte@Sun.COM 
39517836SJohn.Forte@Sun.COM 	if (task->task_additional_flags &
39527836SJohn.Forte@Sun.COM 	    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
39537836SJohn.Forte@Sun.COM 		task->task_expected_xfer_length =
39547836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length;
39557836SJohn.Forte@Sun.COM 	}
39567836SJohn.Forte@Sun.COM 
39577836SJohn.Forte@Sun.COM 	if (task->task_cmd_xfer_length < 16) {
39587836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
39597836SJohn.Forte@Sun.COM 			STMF_SAA_INVALID_FIELD_IN_CDB);
39607836SJohn.Forte@Sun.COM 		return;
39617836SJohn.Forte@Sun.COM 	}
39627836SJohn.Forte@Sun.COM 
39637836SJohn.Forte@Sun.COM 	sz = min(task->task_expected_xfer_length,
39647836SJohn.Forte@Sun.COM 	    task->task_cmd_xfer_length);
39657836SJohn.Forte@Sun.COM 
39667836SJohn.Forte@Sun.COM 	xd = stmf_prepare_tpgs_data();
39677836SJohn.Forte@Sun.COM 
39687836SJohn.Forte@Sun.COM 	if (xd == NULL) {
39697836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
39707836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
39717836SJohn.Forte@Sun.COM 		return;
39727836SJohn.Forte@Sun.COM 	}
39737836SJohn.Forte@Sun.COM 
39747836SJohn.Forte@Sun.COM 	sz = min(sz, xd->size_left);
39757836SJohn.Forte@Sun.COM 	xd->size_left = sz;
39767836SJohn.Forte@Sun.COM 	minsz = min(512, sz);
39777836SJohn.Forte@Sun.COM 
39787836SJohn.Forte@Sun.COM 	if (dbuf == NULL)
39797836SJohn.Forte@Sun.COM 		dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
39807836SJohn.Forte@Sun.COM 	if (dbuf == NULL) {
39817836SJohn.Forte@Sun.COM 		kmem_free(xd, xd->alloc_size);
39827836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
39837836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
39847836SJohn.Forte@Sun.COM 		return;
39857836SJohn.Forte@Sun.COM 	}
39867836SJohn.Forte@Sun.COM 	dbuf->db_lu_private = xd;
39877836SJohn.Forte@Sun.COM 	stmf_xd_to_dbuf(dbuf);
39887836SJohn.Forte@Sun.COM 
39897836SJohn.Forte@Sun.COM 	dbuf->db_flags = DB_DIRECTION_TO_RPORT;
39907836SJohn.Forte@Sun.COM 	(void) stmf_xfer_data(task, dbuf, 0);
39917836SJohn.Forte@Sun.COM 
39927836SJohn.Forte@Sun.COM }
39937836SJohn.Forte@Sun.COM 
39947836SJohn.Forte@Sun.COM void
39957836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task)
39967836SJohn.Forte@Sun.COM {
39977836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
39987836SJohn.Forte@Sun.COM 	/*
39997836SJohn.Forte@Sun.COM 	 * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET
40007836SJohn.Forte@Sun.COM 	 * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state
40017836SJohn.Forte@Sun.COM 	 * in these cases. This needs to be changed to abort only the required
40027836SJohn.Forte@Sun.COM 	 * set.
40037836SJohn.Forte@Sun.COM 	 */
40047836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
40057836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
40067836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
40077836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
40087836SJohn.Forte@Sun.COM 		stmf_handle_lun_reset(task);
40097836SJohn.Forte@Sun.COM 		return;
40107836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
40117836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
40127836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
40137836SJohn.Forte@Sun.COM 		stmf_handle_target_reset(task);
40147836SJohn.Forte@Sun.COM 		return;
40157836SJohn.Forte@Sun.COM 	default:
40167836SJohn.Forte@Sun.COM 		/* We dont support this task mgmt function */
40177836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
40187836SJohn.Forte@Sun.COM 		    STMF_SAA_INVALID_FIELD_IN_CMD_IU);
40197836SJohn.Forte@Sun.COM 		return;
40207836SJohn.Forte@Sun.COM 	}
40217836SJohn.Forte@Sun.COM }
40227836SJohn.Forte@Sun.COM 
40237836SJohn.Forte@Sun.COM void
40247836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task)
40257836SJohn.Forte@Sun.COM {
40267836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
40277836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
40287836SJohn.Forte@Sun.COM 
40297836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
40307836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
40317836SJohn.Forte@Sun.COM 
40327836SJohn.Forte@Sun.COM 	/*
40337836SJohn.Forte@Sun.COM 	 * To sync with target reset, grab this lock. The LU is not going
40347836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
40357836SJohn.Forte@Sun.COM 	 */
40367836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
40377836SJohn.Forte@Sun.COM 
40387836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
40397836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40407836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
40417836SJohn.Forte@Sun.COM 				STMF_SAA_OPERATION_IN_PROGRESS);
40427836SJohn.Forte@Sun.COM 		return;
40437836SJohn.Forte@Sun.COM 	}
40447836SJohn.Forte@Sun.COM 	atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
40457836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
40467836SJohn.Forte@Sun.COM 
40477836SJohn.Forte@Sun.COM 	/*
40487836SJohn.Forte@Sun.COM 	 * Mark this task as the one causing LU reset so that we know who
40497836SJohn.Forte@Sun.COM 	 * was responsible for setting the ILU_RESET_ACTIVE. In case this
40507836SJohn.Forte@Sun.COM 	 * task itself gets aborted, we will clear ILU_RESET_ACTIVE.
40517836SJohn.Forte@Sun.COM 	 */
40527836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET;
40537836SJohn.Forte@Sun.COM 
40547836SJohn.Forte@Sun.COM 	/* Initiatiate abort on all commands on this LU except this one */
40557836SJohn.Forte@Sun.COM 	stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu);
40567836SJohn.Forte@Sun.COM 
40577836SJohn.Forte@Sun.COM 	/* Start polling on this task */
40587836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
40597836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
40607836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
40617836SJohn.Forte@Sun.COM 						NULL);
40627836SJohn.Forte@Sun.COM 		return;
40637836SJohn.Forte@Sun.COM 	}
40647836SJohn.Forte@Sun.COM }
40657836SJohn.Forte@Sun.COM 
40667836SJohn.Forte@Sun.COM void
40677836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task)
40687836SJohn.Forte@Sun.COM {
40697836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
40707836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
40717836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
40727836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
40737836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
40747836SJohn.Forte@Sun.COM 	int i, lf;
40757836SJohn.Forte@Sun.COM 
40767836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
40777836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private;
40787836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
40797836SJohn.Forte@Sun.COM 
40807836SJohn.Forte@Sun.COM 	/*
40817836SJohn.Forte@Sun.COM 	 * To sync with LUN reset, grab this lock. The session is not going
40827836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
40837836SJohn.Forte@Sun.COM 	 */
40847836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
4085*7979SSumit.Gupta@Sun.COM 
4086*7979SSumit.Gupta@Sun.COM 	/* Grab the session lock as a writer to prevent any changes in it */
4087*7979SSumit.Gupta@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
4088*7979SSumit.Gupta@Sun.COM 
40897836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_RESET_ACTIVE) {
4090*7979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
40917836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40927836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
40937836SJohn.Forte@Sun.COM 				STMF_SAA_OPERATION_IN_PROGRESS);
40947836SJohn.Forte@Sun.COM 		return;
40957836SJohn.Forte@Sun.COM 	}
40967836SJohn.Forte@Sun.COM 	atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE);
40977836SJohn.Forte@Sun.COM 
40987836SJohn.Forte@Sun.COM 	/*
40997836SJohn.Forte@Sun.COM 	 * Now go through each LUN in this session and make sure all of them
41007836SJohn.Forte@Sun.COM 	 * can be reset.
41017836SJohn.Forte@Sun.COM 	 */
41027836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
41037836SJohn.Forte@Sun.COM 	for (i = 0, lf = 0; i < lm->lm_nentries; i++) {
41047836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
41057836SJohn.Forte@Sun.COM 			continue;
41067836SJohn.Forte@Sun.COM 		lf++;
41077836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
41087836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
41097836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
41107836SJohn.Forte@Sun.COM 			atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
4111*7979SSumit.Gupta@Sun.COM 			rw_exit(iss->iss_lockp);
41127836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
41137836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
41147836SJohn.Forte@Sun.COM 					STMF_SAA_OPERATION_IN_PROGRESS);
41157836SJohn.Forte@Sun.COM 			return;
41167836SJohn.Forte@Sun.COM 		}
41177836SJohn.Forte@Sun.COM 	}
41187836SJohn.Forte@Sun.COM 	if (lf == 0) {
41197836SJohn.Forte@Sun.COM 		/* No luns in this session */
41207836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
4121*7979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
41227836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41237836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
41247836SJohn.Forte@Sun.COM 		return;
41257836SJohn.Forte@Sun.COM 	}
41267836SJohn.Forte@Sun.COM 
41277836SJohn.Forte@Sun.COM 	/* ok, start the damage */
41287836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING |
41297836SJohn.Forte@Sun.COM 					ITASK_CAUSING_TARGET_RESET;
41307836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
41317836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
41327836SJohn.Forte@Sun.COM 			continue;
41337836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
41347836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
41357836SJohn.Forte@Sun.COM 		atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
41367836SJohn.Forte@Sun.COM 	}
4137*7979SSumit.Gupta@Sun.COM 	rw_exit(iss->iss_lockp);
41387836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
41397836SJohn.Forte@Sun.COM 
41407836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
41417836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
41427836SJohn.Forte@Sun.COM 			continue;
41437836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
41447836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
41457836SJohn.Forte@Sun.COM 				lm_ent->ent_lu);
41467836SJohn.Forte@Sun.COM 	}
41477836SJohn.Forte@Sun.COM 
41487836SJohn.Forte@Sun.COM 	/* Start polling on this task */
41497836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
41507836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
41517836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
41527836SJohn.Forte@Sun.COM 						NULL);
41537836SJohn.Forte@Sun.COM 		return;
41547836SJohn.Forte@Sun.COM 	}
41557836SJohn.Forte@Sun.COM }
41567836SJohn.Forte@Sun.COM 
41577836SJohn.Forte@Sun.COM int
41587836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask)
41597836SJohn.Forte@Sun.COM {
41607836SJohn.Forte@Sun.COM 	scsi_task_t *task = itask->itask_task;
41617836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
41627836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
41637836SJohn.Forte@Sun.COM 
41647836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
41657836SJohn.Forte@Sun.COM 	if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) ||
41667836SJohn.Forte@Sun.COM 	    (task->task_cdb[0] == SCMD_INQUIRY)) {
41677836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
41687836SJohn.Forte@Sun.COM 		return (0);
41697836SJohn.Forte@Sun.COM 	}
41707836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
41717836SJohn.Forte@Sun.COM 		~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
41727836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
41737836SJohn.Forte@Sun.COM 
41747836SJohn.Forte@Sun.COM 	if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
41757836SJohn.Forte@Sun.COM 		return (0);
41767836SJohn.Forte@Sun.COM 	}
41777836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK,
41787836SJohn.Forte@Sun.COM 	    STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED);
41797836SJohn.Forte@Sun.COM 	return (1);
41807836SJohn.Forte@Sun.COM }
41817836SJohn.Forte@Sun.COM 
41827836SJohn.Forte@Sun.COM void
41837836SJohn.Forte@Sun.COM stmf_worker_init()
41847836SJohn.Forte@Sun.COM {
41857836SJohn.Forte@Sun.COM 	uint32_t i;
41867836SJohn.Forte@Sun.COM 
41877836SJohn.Forte@Sun.COM 	/* Make local copy of global tunables */
41887836SJohn.Forte@Sun.COM 	stmf_i_max_nworkers = stmf_max_nworkers;
41897836SJohn.Forte@Sun.COM 	stmf_i_min_nworkers = stmf_min_nworkers;
41907836SJohn.Forte@Sun.COM 
41917836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers == NULL);
41927836SJohn.Forte@Sun.COM 	if (stmf_i_min_nworkers < 4) {
41937836SJohn.Forte@Sun.COM 		stmf_i_min_nworkers = 4;
41947836SJohn.Forte@Sun.COM 	}
41957836SJohn.Forte@Sun.COM 	if (stmf_i_max_nworkers < stmf_i_min_nworkers) {
41967836SJohn.Forte@Sun.COM 		stmf_i_max_nworkers = stmf_i_min_nworkers;
41977836SJohn.Forte@Sun.COM 	}
41987836SJohn.Forte@Sun.COM 	stmf_workers = (stmf_worker_t *)kmem_zalloc(
41997836SJohn.Forte@Sun.COM 	    sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP);
42007836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
42017836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
42027836SJohn.Forte@Sun.COM 		mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
42037836SJohn.Forte@Sun.COM 		cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
42047836SJohn.Forte@Sun.COM 	}
42057836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
42067836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_ENABLED;
42077836SJohn.Forte@Sun.COM 
42087836SJohn.Forte@Sun.COM 	/* Workers will be started by stmf_worker_mgmt() */
42097836SJohn.Forte@Sun.COM 
42107836SJohn.Forte@Sun.COM 	/* Lets wait for atleast one worker to start */
42117836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur == 0)
42127836SJohn.Forte@Sun.COM 		delay(drv_usectohz(20 * 1000));
42137836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000);
42147836SJohn.Forte@Sun.COM }
42157836SJohn.Forte@Sun.COM 
42167836SJohn.Forte@Sun.COM stmf_status_t
42177836SJohn.Forte@Sun.COM stmf_worker_fini()
42187836SJohn.Forte@Sun.COM {
42197836SJohn.Forte@Sun.COM 	int i;
42207836SJohn.Forte@Sun.COM 	clock_t sb;
42217836SJohn.Forte@Sun.COM 
42227836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED)
42237836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
42247836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers);
42257836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_DISABLED;
42267836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
42277836SJohn.Forte@Sun.COM 	cv_signal(&stmf_state.stmf_cv);
42287836SJohn.Forte@Sun.COM 
42297836SJohn.Forte@Sun.COM 	sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000);
42307836SJohn.Forte@Sun.COM 	/* Wait for all the threads to die */
42317836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur != 0) {
42327836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > sb) {
42337836SJohn.Forte@Sun.COM 			stmf_workers_state = STMF_WORKERS_ENABLED;
42347836SJohn.Forte@Sun.COM 			return (STMF_BUSY);
42357836SJohn.Forte@Sun.COM 		}
42367836SJohn.Forte@Sun.COM 		delay(drv_usectohz(100 * 1000));
42377836SJohn.Forte@Sun.COM 	}
42387836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
42397836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
42407836SJohn.Forte@Sun.COM 		mutex_destroy(&w->worker_lock);
42417836SJohn.Forte@Sun.COM 		cv_destroy(&w->worker_cv);
42427836SJohn.Forte@Sun.COM 	}
42437836SJohn.Forte@Sun.COM 	kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers);
42447836SJohn.Forte@Sun.COM 	stmf_workers = NULL;
42457836SJohn.Forte@Sun.COM 
42467836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
42477836SJohn.Forte@Sun.COM }
42487836SJohn.Forte@Sun.COM 
42497836SJohn.Forte@Sun.COM void
42507836SJohn.Forte@Sun.COM stmf_worker_task(void *arg)
42517836SJohn.Forte@Sun.COM {
42527836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
42537836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
42547836SJohn.Forte@Sun.COM 	scsi_task_t *task;
42557836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
42567836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
42577836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
42587836SJohn.Forte@Sun.COM 	clock_t wait_timer = 0;
42597836SJohn.Forte@Sun.COM 	clock_t wait_ticks;
42607836SJohn.Forte@Sun.COM 	uint32_t old, new;
42617836SJohn.Forte@Sun.COM 	uint8_t curcmd;
42627836SJohn.Forte@Sun.COM 	uint8_t abort_free;
42637836SJohn.Forte@Sun.COM 	uint8_t wait_queue;
42647836SJohn.Forte@Sun.COM 	uint8_t dec_qdepth;
42657836SJohn.Forte@Sun.COM 
42667836SJohn.Forte@Sun.COM 	w = (stmf_worker_t *)arg;
42677836SJohn.Forte@Sun.COM 	wait_ticks = drv_usectohz(10000);
42687836SJohn.Forte@Sun.COM 
42697836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
42707836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE;
42717836SJohn.Forte@Sun.COM stmf_worker_loop:;
42727836SJohn.Forte@Sun.COM 	if ((w->worker_ref_count == 0) &&
42737836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
42747836SJohn.Forte@Sun.COM 		w->worker_flags &= ~(STMF_WORKER_STARTED |
42757836SJohn.Forte@Sun.COM 		    STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE);
42767836SJohn.Forte@Sun.COM 		w->worker_tid = NULL;
42777836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
42787836SJohn.Forte@Sun.COM 		thread_exit();
42797836SJohn.Forte@Sun.COM 	}
42807836SJohn.Forte@Sun.COM 	/* CONSTCOND */
42817836SJohn.Forte@Sun.COM 	while (1) {
42827836SJohn.Forte@Sun.COM 		dec_qdepth = 0;
42837836SJohn.Forte@Sun.COM 		if (wait_timer && (ddi_get_lbolt() >= wait_timer)) {
42847836SJohn.Forte@Sun.COM 			wait_timer = 0;
4285*7979SSumit.Gupta@Sun.COM 			if (w->worker_wait_head) {
4286*7979SSumit.Gupta@Sun.COM 				ASSERT(w->worker_wait_tail);
4287*7979SSumit.Gupta@Sun.COM 				if (w->worker_task_head == NULL)
4288*7979SSumit.Gupta@Sun.COM 					w->worker_task_head =
4289*7979SSumit.Gupta@Sun.COM 					    w->worker_wait_head;
4290*7979SSumit.Gupta@Sun.COM 				else
4291*7979SSumit.Gupta@Sun.COM 					w->worker_task_tail->itask_worker_next =
4292*7979SSumit.Gupta@Sun.COM 						w->worker_wait_head;
4293*7979SSumit.Gupta@Sun.COM 				w->worker_task_tail = w->worker_wait_tail;
4294*7979SSumit.Gupta@Sun.COM 				w->worker_wait_head = w->worker_wait_tail =
4295*7979SSumit.Gupta@Sun.COM 				    NULL;
4296*7979SSumit.Gupta@Sun.COM 			}
42977836SJohn.Forte@Sun.COM 		}
42987836SJohn.Forte@Sun.COM 		if ((itask = w->worker_task_head) == NULL) {
42997836SJohn.Forte@Sun.COM 			break;
43007836SJohn.Forte@Sun.COM 		}
43017836SJohn.Forte@Sun.COM 		task = itask->itask_task;
43027836SJohn.Forte@Sun.COM 		w->worker_task_head = itask->itask_worker_next;
43037836SJohn.Forte@Sun.COM 		if (w->worker_task_head == NULL)
43047836SJohn.Forte@Sun.COM 			w->worker_task_tail = NULL;
43057836SJohn.Forte@Sun.COM 
43067836SJohn.Forte@Sun.COM 		wait_queue = 0;
43077836SJohn.Forte@Sun.COM 		abort_free = 0;
43087836SJohn.Forte@Sun.COM 		if (itask->itask_ncmds > 0) {
43097836SJohn.Forte@Sun.COM 			curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1];
43107836SJohn.Forte@Sun.COM 		} else {
43117836SJohn.Forte@Sun.COM 			ASSERT(itask->itask_flags & ITASK_BEING_ABORTED);
43127836SJohn.Forte@Sun.COM 		}
43137836SJohn.Forte@Sun.COM 		do {
43147836SJohn.Forte@Sun.COM 			old = itask->itask_flags;
43157836SJohn.Forte@Sun.COM 			if (old & ITASK_BEING_ABORTED) {
43167836SJohn.Forte@Sun.COM 				itask->itask_ncmds = 1;
43177836SJohn.Forte@Sun.COM 				curcmd = itask->itask_cmd_stack[0] =
43187836SJohn.Forte@Sun.COM 				    ITASK_CMD_ABORT;
43197836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
43207836SJohn.Forte@Sun.COM 			} else if ((curcmd & ITASK_CMD_MASK) ==
43217836SJohn.Forte@Sun.COM 			    ITASK_CMD_NEW_TASK) {
43227836SJohn.Forte@Sun.COM 				new = old | ITASK_KNOWN_TO_LU;
43237836SJohn.Forte@Sun.COM 			} else {
43247836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
43257836SJohn.Forte@Sun.COM 			}
43267836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
43277836SJohn.Forte@Sun.COM 
43287836SJohn.Forte@Sun.COM out_itask_flag_loop:
43297836SJohn.Forte@Sun.COM 
43307836SJohn.Forte@Sun.COM 		/*
43317836SJohn.Forte@Sun.COM 		 * Decide if this task needs to go to a queue and/or if
43327836SJohn.Forte@Sun.COM 		 * we can decrement the itask_cmd_stack.
43337836SJohn.Forte@Sun.COM 		 */
43347836SJohn.Forte@Sun.COM 		if (curcmd == ITASK_CMD_ABORT) {
43357836SJohn.Forte@Sun.COM 			if (itask->itask_flags & (ITASK_KNOWN_TO_LU |
43367836SJohn.Forte@Sun.COM 			    ITASK_KNOWN_TO_TGT_PORT)) {
43377836SJohn.Forte@Sun.COM 				wait_queue = 1;
43387836SJohn.Forte@Sun.COM 			} else {
43397836SJohn.Forte@Sun.COM 				abort_free = 1;
43407836SJohn.Forte@Sun.COM 			}
43417836SJohn.Forte@Sun.COM 		} else if ((curcmd & ITASK_CMD_POLL) &&
43427836SJohn.Forte@Sun.COM 		    (itask->itask_poll_timeout > ddi_get_lbolt())) {
43437836SJohn.Forte@Sun.COM 			wait_queue = 1;
43447836SJohn.Forte@Sun.COM 		}
43457836SJohn.Forte@Sun.COM 
43467836SJohn.Forte@Sun.COM 		if (wait_queue) {
43477836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
43487836SJohn.Forte@Sun.COM 			if (w->worker_wait_tail) {
43497836SJohn.Forte@Sun.COM 				w->worker_wait_tail->itask_worker_next = itask;
43507836SJohn.Forte@Sun.COM 			} else {
43517836SJohn.Forte@Sun.COM 				w->worker_wait_head = itask;
43527836SJohn.Forte@Sun.COM 			}
43537836SJohn.Forte@Sun.COM 			w->worker_wait_tail = itask;
43547836SJohn.Forte@Sun.COM 			if (wait_timer == 0) {
43557836SJohn.Forte@Sun.COM 				wait_timer = ddi_get_lbolt() + wait_ticks;
43567836SJohn.Forte@Sun.COM 			}
43577836SJohn.Forte@Sun.COM 		} else if ((--(itask->itask_ncmds)) != 0) {
43587836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
43597836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
43607836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
43617836SJohn.Forte@Sun.COM 			} else {
43627836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
43637836SJohn.Forte@Sun.COM 			}
43647836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
43657836SJohn.Forte@Sun.COM 		} else {
43667836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
43677836SJohn.Forte@Sun.COM 			    ~ITASK_IN_WORKER_QUEUE);
43687836SJohn.Forte@Sun.COM 			/*
43697836SJohn.Forte@Sun.COM 			 * This is where the queue depth should go down by
43707836SJohn.Forte@Sun.COM 			 * one but we delay that on purpose to account for
43717836SJohn.Forte@Sun.COM 			 * the call into the provider. The actual decrement
43727836SJohn.Forte@Sun.COM 			 * happens after the worker has done its job.
43737836SJohn.Forte@Sun.COM 			 */
43747836SJohn.Forte@Sun.COM 			dec_qdepth = 1;
43757836SJohn.Forte@Sun.COM 		}
43767836SJohn.Forte@Sun.COM 
43777836SJohn.Forte@Sun.COM 		/* We made it here means we are going to call LU */
43787836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0)
43797836SJohn.Forte@Sun.COM 			lu = task->task_lu;
43807836SJohn.Forte@Sun.COM 		else
43817836SJohn.Forte@Sun.COM 			lu = dlun0;
43827836SJohn.Forte@Sun.COM 		dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)];
43837836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
43847836SJohn.Forte@Sun.COM 		curcmd &= ITASK_CMD_MASK;
43857836SJohn.Forte@Sun.COM 		switch (curcmd) {
43867836SJohn.Forte@Sun.COM 		case ITASK_CMD_NEW_TASK:
43877836SJohn.Forte@Sun.COM 			iss = (stmf_i_scsi_session_t *)
43887836SJohn.Forte@Sun.COM 			    task->task_session->ss_stmf_private;
43897836SJohn.Forte@Sun.COM 			if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) {
43907836SJohn.Forte@Sun.COM 				if (stmf_handle_cmd_during_ic(itask))
43917836SJohn.Forte@Sun.COM 					break;
43927836SJohn.Forte@Sun.COM 			}
43937836SJohn.Forte@Sun.COM #ifdef	DEBUG
43947836SJohn.Forte@Sun.COM 			if (stmf_drop_task_counter > 0) {
43957836SJohn.Forte@Sun.COM 				if (atomic_add_32_nv(
43967836SJohn.Forte@Sun.COM 				    (uint32_t *)&stmf_drop_task_counter,
43977836SJohn.Forte@Sun.COM 				    -1) == 1) {
43987836SJohn.Forte@Sun.COM 					break;
43997836SJohn.Forte@Sun.COM 				}
44007836SJohn.Forte@Sun.COM 			}
44017836SJohn.Forte@Sun.COM #endif
44027836SJohn.Forte@Sun.COM 			lu->lu_new_task(task, dbuf);
44037836SJohn.Forte@Sun.COM 			break;
44047836SJohn.Forte@Sun.COM 		case ITASK_CMD_DATA_XFER_DONE:
44057836SJohn.Forte@Sun.COM 			lu->lu_dbuf_xfer_done(task, dbuf);
44067836SJohn.Forte@Sun.COM 			break;
44077836SJohn.Forte@Sun.COM 		case ITASK_CMD_STATUS_DONE:
44087836SJohn.Forte@Sun.COM 			lu->lu_send_status_done(task);
44097836SJohn.Forte@Sun.COM 			break;
44107836SJohn.Forte@Sun.COM 		case ITASK_CMD_ABORT:
44117836SJohn.Forte@Sun.COM 			if (abort_free) {
44127836SJohn.Forte@Sun.COM 				stmf_task_free(task);
44137836SJohn.Forte@Sun.COM 			} else {
44147836SJohn.Forte@Sun.COM 				stmf_do_task_abort(task);
44157836SJohn.Forte@Sun.COM 			}
44167836SJohn.Forte@Sun.COM 			break;
44177836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LU:
44187836SJohn.Forte@Sun.COM 			if (!wait_queue) {
44197836SJohn.Forte@Sun.COM 				lu->lu_task_poll(task);
44207836SJohn.Forte@Sun.COM 			}
44217836SJohn.Forte@Sun.COM 			break;
44227836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LPORT:
44237836SJohn.Forte@Sun.COM 			if (!wait_queue)
44247836SJohn.Forte@Sun.COM 				task->task_lport->lport_task_poll(task);
44257836SJohn.Forte@Sun.COM 			break;
44267836SJohn.Forte@Sun.COM 		case ITASK_CMD_SEND_STATUS:
44277836SJohn.Forte@Sun.COM 		/* case ITASK_CMD_XFER_DATA: */
44287836SJohn.Forte@Sun.COM 			break;
44297836SJohn.Forte@Sun.COM 		}
44307836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
44317836SJohn.Forte@Sun.COM 		if (dec_qdepth) {
44327836SJohn.Forte@Sun.COM 			w->worker_queue_depth--;
44337836SJohn.Forte@Sun.COM 		}
44347836SJohn.Forte@Sun.COM 	}
44357836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) {
44367836SJohn.Forte@Sun.COM 		if (w->worker_ref_count == 0)
44377836SJohn.Forte@Sun.COM 			goto stmf_worker_loop;
44387836SJohn.Forte@Sun.COM 		else
44397836SJohn.Forte@Sun.COM 			wait_timer = ddi_get_lbolt() + 1;
44407836SJohn.Forte@Sun.COM 	}
44417836SJohn.Forte@Sun.COM 	w->worker_flags &= ~STMF_WORKER_ACTIVE;
44427836SJohn.Forte@Sun.COM 	if (wait_timer) {
44437836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer);
44447836SJohn.Forte@Sun.COM 	} else {
44457836SJohn.Forte@Sun.COM 		cv_wait(&w->worker_cv, &w->worker_lock);
44467836SJohn.Forte@Sun.COM 	}
44477836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_ACTIVE;
44487836SJohn.Forte@Sun.COM 	goto stmf_worker_loop;
44497836SJohn.Forte@Sun.COM }
44507836SJohn.Forte@Sun.COM 
44517836SJohn.Forte@Sun.COM void
44527836SJohn.Forte@Sun.COM stmf_worker_mgmt()
44537836SJohn.Forte@Sun.COM {
44547836SJohn.Forte@Sun.COM 	int i;
44557836SJohn.Forte@Sun.COM 	int workers_needed;
44567836SJohn.Forte@Sun.COM 	uint32_t qd;
44577836SJohn.Forte@Sun.COM 	clock_t tps, d = 0;
44587836SJohn.Forte@Sun.COM 	uint32_t cur_max_ntasks = 0;
44597836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
44607836SJohn.Forte@Sun.COM 
44617836SJohn.Forte@Sun.COM 	/* Check if we are trying to increase the # of threads */
44627836SJohn.Forte@Sun.COM 	for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) {
44637836SJohn.Forte@Sun.COM 		if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) {
44647836SJohn.Forte@Sun.COM 			stmf_nworkers_cur++;
44657836SJohn.Forte@Sun.COM 			stmf_nworkers_accepting_cmds++;
44667836SJohn.Forte@Sun.COM 		} else {
44677836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
44687836SJohn.Forte@Sun.COM 			return;
44697836SJohn.Forte@Sun.COM 		}
44707836SJohn.Forte@Sun.COM 	}
44717836SJohn.Forte@Sun.COM 	/* Check if we are trying to decrease the # of workers */
44727836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
44737836SJohn.Forte@Sun.COM 		if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) {
44747836SJohn.Forte@Sun.COM 			stmf_nworkers_cur--;
44757836SJohn.Forte@Sun.COM 			/*
44767836SJohn.Forte@Sun.COM 			 * stmf_nworkers_accepting_cmds has already been
44777836SJohn.Forte@Sun.COM 			 * updated by the request to reduce the # of workers.
44787836SJohn.Forte@Sun.COM 			 */
44797836SJohn.Forte@Sun.COM 		} else {
44807836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
44817836SJohn.Forte@Sun.COM 			return;
44827836SJohn.Forte@Sun.COM 		}
44837836SJohn.Forte@Sun.COM 	}
44847836SJohn.Forte@Sun.COM 	/* Check if we are being asked to quit */
44857836SJohn.Forte@Sun.COM 	if (stmf_workers_state != STMF_WORKERS_ENABLED) {
44867836SJohn.Forte@Sun.COM 		if (stmf_nworkers_cur) {
44877836SJohn.Forte@Sun.COM 			workers_needed = 0;
44887836SJohn.Forte@Sun.COM 			goto worker_mgmt_trigger_change;
44897836SJohn.Forte@Sun.COM 		}
44907836SJohn.Forte@Sun.COM 		return;
44917836SJohn.Forte@Sun.COM 	}
44927836SJohn.Forte@Sun.COM 	/* Check if we are starting */
44937836SJohn.Forte@Sun.COM 	if (stmf_nworkers_cur < stmf_i_min_nworkers) {
44947836SJohn.Forte@Sun.COM 		workers_needed = stmf_i_min_nworkers;
44957836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
44967836SJohn.Forte@Sun.COM 	}
44977836SJohn.Forte@Sun.COM 
44987836SJohn.Forte@Sun.COM 	tps = drv_usectohz(1 * 1000 * 1000);
44997836SJohn.Forte@Sun.COM 	if ((stmf_wm_last != 0) &&
45007836SJohn.Forte@Sun.COM 	    ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) {
45017836SJohn.Forte@Sun.COM 		qd = 0;
45027836SJohn.Forte@Sun.COM 		for (i = 0; i < stmf_nworkers_accepting_cmds; i++) {
45037836SJohn.Forte@Sun.COM 			qd += stmf_workers[i].worker_max_qdepth_pu;
45047836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_qdepth_pu = 0;
45057836SJohn.Forte@Sun.COM 			if (stmf_workers[i].worker_max_sys_qdepth_pu >
45067836SJohn.Forte@Sun.COM 			    cur_max_ntasks) {
45077836SJohn.Forte@Sun.COM 				cur_max_ntasks =
45087836SJohn.Forte@Sun.COM 				    stmf_workers[i].worker_max_sys_qdepth_pu;
45097836SJohn.Forte@Sun.COM 			}
45107836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_sys_qdepth_pu = 0;
45117836SJohn.Forte@Sun.COM 		}
45127836SJohn.Forte@Sun.COM 	}
45137836SJohn.Forte@Sun.COM 	stmf_wm_last = ddi_get_lbolt();
45147836SJohn.Forte@Sun.COM 	if (d <= tps) {
45157836SJohn.Forte@Sun.COM 		/* still ramping up */
45167836SJohn.Forte@Sun.COM 		return;
45177836SJohn.Forte@Sun.COM 	}
45187836SJohn.Forte@Sun.COM 	/* max qdepth cannot be more than max tasks */
45197836SJohn.Forte@Sun.COM 	if (qd > cur_max_ntasks)
45207836SJohn.Forte@Sun.COM 		qd = cur_max_ntasks;
45217836SJohn.Forte@Sun.COM 
45227836SJohn.Forte@Sun.COM 	/* See if we have more workers */
45237836SJohn.Forte@Sun.COM 	if (qd < stmf_nworkers_accepting_cmds) {
45247836SJohn.Forte@Sun.COM 		/*
45257836SJohn.Forte@Sun.COM 		 * Since we dont reduce the worker count right away, monitor
45267836SJohn.Forte@Sun.COM 		 * the highest load during the scale_down_delay.
45277836SJohn.Forte@Sun.COM 		 */
45287836SJohn.Forte@Sun.COM 		if (qd > stmf_worker_scale_down_qd)
45297836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = qd;
45307836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_timer == 0) {
45317836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_timer = ddi_get_lbolt() +
45327836SJohn.Forte@Sun.COM 			    drv_usectohz(stmf_worker_scale_down_delay *
45337836SJohn.Forte@Sun.COM 			    1000 * 1000);
45347836SJohn.Forte@Sun.COM 			return;
45357836SJohn.Forte@Sun.COM 		}
45367836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() < stmf_worker_scale_down_timer) {
45377836SJohn.Forte@Sun.COM 			return;
45387836SJohn.Forte@Sun.COM 		}
45397836SJohn.Forte@Sun.COM 		/* Its time to reduce the workers */
45407836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd < stmf_i_min_nworkers)
45417836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_min_nworkers;
45427836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd > stmf_i_max_nworkers)
45437836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_max_nworkers;
45447836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd == stmf_nworkers_cur)
45457836SJohn.Forte@Sun.COM 			return;
45467836SJohn.Forte@Sun.COM 		workers_needed = stmf_worker_scale_down_qd;
45477836SJohn.Forte@Sun.COM 		stmf_worker_scale_down_qd = 0;
45487836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
45497836SJohn.Forte@Sun.COM 	}
45507836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_qd = 0;
45517836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_timer = 0;
45527836SJohn.Forte@Sun.COM 	if (qd > stmf_i_max_nworkers)
45537836SJohn.Forte@Sun.COM 		qd = stmf_i_max_nworkers;
45547836SJohn.Forte@Sun.COM 	if (qd < stmf_i_min_nworkers)
45557836SJohn.Forte@Sun.COM 		qd = stmf_i_min_nworkers;
45567836SJohn.Forte@Sun.COM 	if (qd == stmf_nworkers_cur)
45577836SJohn.Forte@Sun.COM 		return;
45587836SJohn.Forte@Sun.COM 	workers_needed = qd;
45597836SJohn.Forte@Sun.COM 	goto worker_mgmt_trigger_change;
45607836SJohn.Forte@Sun.COM 
45617836SJohn.Forte@Sun.COM 	/* NOTREACHED */
45627836SJohn.Forte@Sun.COM 	return;
45637836SJohn.Forte@Sun.COM 
45647836SJohn.Forte@Sun.COM worker_mgmt_trigger_change:
45657836SJohn.Forte@Sun.COM 	ASSERT(workers_needed != stmf_nworkers_cur);
45667836SJohn.Forte@Sun.COM 	if (workers_needed > stmf_nworkers_cur) {
45677836SJohn.Forte@Sun.COM 		stmf_nworkers_needed = workers_needed;
45687836SJohn.Forte@Sun.COM 		for (i = stmf_nworkers_cur; i < workers_needed; i++) {
45697836SJohn.Forte@Sun.COM 			w = &stmf_workers[i];
45707836SJohn.Forte@Sun.COM 			w->worker_tid = thread_create(NULL, 0, stmf_worker_task,
45717836SJohn.Forte@Sun.COM 			    (void *)&stmf_workers[i], 0, &p0, TS_RUN,
45727836SJohn.Forte@Sun.COM 			    minclsyspri);
45737836SJohn.Forte@Sun.COM 		}
45747836SJohn.Forte@Sun.COM 		return;
45757836SJohn.Forte@Sun.COM 	}
45767836SJohn.Forte@Sun.COM 	/* At this point we know that we are decreasing the # of workers */
45777836SJohn.Forte@Sun.COM 	stmf_nworkers_accepting_cmds = workers_needed;
45787836SJohn.Forte@Sun.COM 	stmf_nworkers_needed = workers_needed;
45797836SJohn.Forte@Sun.COM 	/* Signal the workers that its time to quit */
45807836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
45817836SJohn.Forte@Sun.COM 		w = &stmf_workers[i];
45827836SJohn.Forte@Sun.COM 		ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED));
45837836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
45847836SJohn.Forte@Sun.COM 		w->worker_flags |= STMF_WORKER_TERMINATE;
45857836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
45867836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
45877836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
45887836SJohn.Forte@Sun.COM 	}
45897836SJohn.Forte@Sun.COM }
45907836SJohn.Forte@Sun.COM 
45917836SJohn.Forte@Sun.COM /*
45927836SJohn.Forte@Sun.COM  * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private).
45937836SJohn.Forte@Sun.COM  * If all the data has been filled out, frees the xd and makes
45947836SJohn.Forte@Sun.COM  * db_lu_private NULL.
45957836SJohn.Forte@Sun.COM  */
45967836SJohn.Forte@Sun.COM void
45977836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf)
45987836SJohn.Forte@Sun.COM {
45997836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
46007836SJohn.Forte@Sun.COM 	uint8_t *p;
46017836SJohn.Forte@Sun.COM 	int i;
46027836SJohn.Forte@Sun.COM 	uint32_t s;
46037836SJohn.Forte@Sun.COM 
46047836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
46057836SJohn.Forte@Sun.COM 	dbuf->db_data_size = 0;
46067836SJohn.Forte@Sun.COM 	dbuf->db_relative_offset = xd->size_done;
46077836SJohn.Forte@Sun.COM 	for (i = 0; i < dbuf->db_sglist_length; i++) {
46087836SJohn.Forte@Sun.COM 		s = min(xd->size_left, dbuf->db_sglist[i].seg_length);
46097836SJohn.Forte@Sun.COM 		p = &xd->buf[xd->size_done];
46107836SJohn.Forte@Sun.COM 		bcopy(p, dbuf->db_sglist[i].seg_addr, s);
46117836SJohn.Forte@Sun.COM 		xd->size_left -= s;
46127836SJohn.Forte@Sun.COM 		xd->size_done += s;
46137836SJohn.Forte@Sun.COM 		dbuf->db_data_size += s;
46147836SJohn.Forte@Sun.COM 		if (xd->size_left == 0) {
46157836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
46167836SJohn.Forte@Sun.COM 			dbuf->db_lu_private = NULL;
46177836SJohn.Forte@Sun.COM 			return;
46187836SJohn.Forte@Sun.COM 		}
46197836SJohn.Forte@Sun.COM 	}
46207836SJohn.Forte@Sun.COM }
46217836SJohn.Forte@Sun.COM 
46227836SJohn.Forte@Sun.COM /* ARGSUSED */
46237836SJohn.Forte@Sun.COM stmf_status_t
46247836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task)
46257836SJohn.Forte@Sun.COM {
46267836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
46277836SJohn.Forte@Sun.COM }
46287836SJohn.Forte@Sun.COM 
46297836SJohn.Forte@Sun.COM void
46307836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
46317836SJohn.Forte@Sun.COM {
46327836SJohn.Forte@Sun.COM 	uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
46337836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
46347836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
46357836SJohn.Forte@Sun.COM 	uint8_t *p;
46367836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
46377836SJohn.Forte@Sun.COM 	uint8_t inq_page_length = 31;
46387836SJohn.Forte@Sun.COM 
46397836SJohn.Forte@Sun.COM 	if (task->task_mgmt_function) {
46407836SJohn.Forte@Sun.COM 		stmf_scsilib_handle_task_mgmt(task);
46417836SJohn.Forte@Sun.COM 		return;
46427836SJohn.Forte@Sun.COM 	}
46437836SJohn.Forte@Sun.COM 
46447836SJohn.Forte@Sun.COM 	switch (cdbp[0]) {
46457836SJohn.Forte@Sun.COM 	case SCMD_INQUIRY:
46467836SJohn.Forte@Sun.COM 		/*
46477836SJohn.Forte@Sun.COM 		 * Basic protocol checks.  In addition, only reply to
46487836SJohn.Forte@Sun.COM 		 * standard inquiry.  Otherwise, the LU provider needs
46497836SJohn.Forte@Sun.COM 		 * to respond.
46507836SJohn.Forte@Sun.COM 		 */
46517836SJohn.Forte@Sun.COM 
46527836SJohn.Forte@Sun.COM 		if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) {
46537836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
46547836SJohn.Forte@Sun.COM 			    STMF_SAA_INVALID_FIELD_IN_CDB);
46557836SJohn.Forte@Sun.COM 			return;
46567836SJohn.Forte@Sun.COM 		}
46577836SJohn.Forte@Sun.COM 
46587836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
46597836SJohn.Forte@Sun.COM 		    (((uint32_t)cdbp[3]) << 8) | cdbp[4];
46607836SJohn.Forte@Sun.COM 
46617836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
46627836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
46637836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
46647836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
46657836SJohn.Forte@Sun.COM 		}
46667836SJohn.Forte@Sun.COM 
46677836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
46687836SJohn.Forte@Sun.COM 		    min(36, task->task_cmd_xfer_length));
46697836SJohn.Forte@Sun.COM 		minsz = 36;
46707836SJohn.Forte@Sun.COM 
46717836SJohn.Forte@Sun.COM 		if (sz == 0) {
46727836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
46737836SJohn.Forte@Sun.COM 			return;
46747836SJohn.Forte@Sun.COM 		}
46757836SJohn.Forte@Sun.COM 
46767836SJohn.Forte@Sun.COM 		if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) {
46777836SJohn.Forte@Sun.COM 			/*
46787836SJohn.Forte@Sun.COM 			 * Ignore any preallocated dbuf if the size is less
46797836SJohn.Forte@Sun.COM 			 * than 36. It will be freed during the task_free.
46807836SJohn.Forte@Sun.COM 			 */
46817836SJohn.Forte@Sun.COM 			dbuf = NULL;
46827836SJohn.Forte@Sun.COM 		}
46837836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
46847836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0);
46857836SJohn.Forte@Sun.COM 		if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) {
46867836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
46877836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
46887836SJohn.Forte@Sun.COM 			return;
46897836SJohn.Forte@Sun.COM 		}
46907836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = NULL;
46917836SJohn.Forte@Sun.COM 
46927836SJohn.Forte@Sun.COM 		p = dbuf->db_sglist[0].seg_addr;
46937836SJohn.Forte@Sun.COM 
46947836SJohn.Forte@Sun.COM 		/*
46957836SJohn.Forte@Sun.COM 		 * Standard inquiry handling only.
46967836SJohn.Forte@Sun.COM 		 */
46977836SJohn.Forte@Sun.COM 
46987836SJohn.Forte@Sun.COM 		bzero(p, inq_page_length + 5);
46997836SJohn.Forte@Sun.COM 
47007836SJohn.Forte@Sun.COM 		p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN;
47017836SJohn.Forte@Sun.COM 		p[2] = 5;
47027836SJohn.Forte@Sun.COM 		p[3] = 0x12;
47037836SJohn.Forte@Sun.COM 		p[4] = inq_page_length;
47047836SJohn.Forte@Sun.COM 		p[6] = 0x80;
47057836SJohn.Forte@Sun.COM 
47067836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+8, "SUN     ", 8);
47077836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+16, "COMSTAR	       ", 16);
47087836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+32, "1.0 ", 4);
47097836SJohn.Forte@Sun.COM 
47107836SJohn.Forte@Sun.COM 		dbuf->db_data_size = sz;
47117836SJohn.Forte@Sun.COM 		dbuf->db_relative_offset = 0;
47127836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
47137836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
47147836SJohn.Forte@Sun.COM 
47157836SJohn.Forte@Sun.COM 		return;
47167836SJohn.Forte@Sun.COM 
47177836SJohn.Forte@Sun.COM 	case SCMD_REPORT_LUNS:
47187836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
47197836SJohn.Forte@Sun.COM 		    ((((uint32_t)task->task_cdb[6]) << 24) |
47207836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[7]) << 16) |
47217836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[8]) << 8) |
47227836SJohn.Forte@Sun.COM 		    ((uint32_t)task->task_cdb[9]));
47237836SJohn.Forte@Sun.COM 
47247836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
47257836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
47267836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
47277836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
47287836SJohn.Forte@Sun.COM 		}
47297836SJohn.Forte@Sun.COM 
47307836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
47317836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length);
47327836SJohn.Forte@Sun.COM 
47337836SJohn.Forte@Sun.COM 		if (sz < 16) {
47347836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
47357836SJohn.Forte@Sun.COM 				STMF_SAA_INVALID_FIELD_IN_CDB);
47367836SJohn.Forte@Sun.COM 			return;
47377836SJohn.Forte@Sun.COM 		}
47387836SJohn.Forte@Sun.COM 
47397836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)
47407836SJohn.Forte@Sun.COM 		    task->task_session->ss_stmf_private;
47417836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
47427836SJohn.Forte@Sun.COM 		xd = stmf_session_prepare_report_lun_data(iss->iss_sm);
47437836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
47447836SJohn.Forte@Sun.COM 
47457836SJohn.Forte@Sun.COM 		if (xd == NULL) {
47467836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
47477836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
47487836SJohn.Forte@Sun.COM 			return;
47497836SJohn.Forte@Sun.COM 		}
47507836SJohn.Forte@Sun.COM 
47517836SJohn.Forte@Sun.COM 		sz = min(sz, xd->size_left);
47527836SJohn.Forte@Sun.COM 		xd->size_left = sz;
47537836SJohn.Forte@Sun.COM 		minsz = min(512, sz);
47547836SJohn.Forte@Sun.COM 
47557836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
47567836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
47577836SJohn.Forte@Sun.COM 		if (dbuf == NULL) {
47587836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
47597836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
47607836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
47617836SJohn.Forte@Sun.COM 			return;
47627836SJohn.Forte@Sun.COM 		}
47637836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = xd;
47647836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
47657836SJohn.Forte@Sun.COM 
47667836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags,
47677836SJohn.Forte@Sun.COM 			~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
47687836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
47697836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
47707836SJohn.Forte@Sun.COM 		return;
47717836SJohn.Forte@Sun.COM 	}
47727836SJohn.Forte@Sun.COM 
47737836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE);
47747836SJohn.Forte@Sun.COM }
47757836SJohn.Forte@Sun.COM 
47767836SJohn.Forte@Sun.COM void
47777836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf)
47787836SJohn.Forte@Sun.COM {
47797836SJohn.Forte@Sun.COM 	if (dbuf->db_xfer_status != STMF_SUCCESS) {
47807836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
47817836SJohn.Forte@Sun.COM 		    dbuf->db_xfer_status, NULL);
47827836SJohn.Forte@Sun.COM 		return;
47837836SJohn.Forte@Sun.COM 	}
47847836SJohn.Forte@Sun.COM 	task->task_nbytes_transferred = dbuf->db_data_size;
47857836SJohn.Forte@Sun.COM 	if (dbuf->db_lu_private) {
47867836SJohn.Forte@Sun.COM 		/* There is more */
47877836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
47887836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
47897836SJohn.Forte@Sun.COM 		return;
47907836SJohn.Forte@Sun.COM 	}
47917836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
47927836SJohn.Forte@Sun.COM }
47937836SJohn.Forte@Sun.COM 
47947836SJohn.Forte@Sun.COM /* ARGSUSED */
47957836SJohn.Forte@Sun.COM void
47967836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task)
47977836SJohn.Forte@Sun.COM {
47987836SJohn.Forte@Sun.COM }
47997836SJohn.Forte@Sun.COM 
48007836SJohn.Forte@Sun.COM /* ARGSUSED */
48017836SJohn.Forte@Sun.COM void
48027836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task)
48037836SJohn.Forte@Sun.COM {
48047836SJohn.Forte@Sun.COM }
48057836SJohn.Forte@Sun.COM 
48067836SJohn.Forte@Sun.COM /* ARGSUSED */
48077836SJohn.Forte@Sun.COM stmf_status_t
48087836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
48097836SJohn.Forte@Sun.COM {
48107836SJohn.Forte@Sun.COM 	scsi_task_t *task = (scsi_task_t *)arg;
48117836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
48127836SJohn.Forte@Sun.COM 			(stmf_i_scsi_task_t *)task->task_stmf_private;
48137836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
48147836SJohn.Forte@Sun.COM 	int i;
48157836SJohn.Forte@Sun.COM 	uint8_t map;
48167836SJohn.Forte@Sun.COM 
48177836SJohn.Forte@Sun.COM 	ASSERT(abort_cmd == STMF_LU_ABORT_TASK);
48187836SJohn.Forte@Sun.COM 	if ((task->task_mgmt_function) && (itask->itask_flags &
48197836SJohn.Forte@Sun.COM 	    (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) {
48207836SJohn.Forte@Sun.COM 		switch (task->task_mgmt_function) {
48217836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK:
48227836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK_SET:
48237836SJohn.Forte@Sun.COM 		case TM_CLEAR_TASK_SET:
48247836SJohn.Forte@Sun.COM 		case TM_LUN_RESET:
48257836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
48267836SJohn.Forte@Sun.COM 			break;
48277836SJohn.Forte@Sun.COM 		case TM_TARGET_RESET:
48287836SJohn.Forte@Sun.COM 		case TM_TARGET_COLD_RESET:
48297836SJohn.Forte@Sun.COM 		case TM_TARGET_WARM_RESET:
48307836SJohn.Forte@Sun.COM 			stmf_abort_target_reset(task);
48317836SJohn.Forte@Sun.COM 			break;
48327836SJohn.Forte@Sun.COM 		}
48337836SJohn.Forte@Sun.COM 		return (STMF_ABORT_SUCCESS);
48347836SJohn.Forte@Sun.COM 	}
48357836SJohn.Forte@Sun.COM 
48367836SJohn.Forte@Sun.COM 	/*
48377836SJohn.Forte@Sun.COM 	 * OK so its not a task mgmt. Make sure we free any xd sitting
48387836SJohn.Forte@Sun.COM 	 * inside any dbuf.
48397836SJohn.Forte@Sun.COM 	 */
48407836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
48417836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
48427836SJohn.Forte@Sun.COM 			if ((map & 1) &&
48437836SJohn.Forte@Sun.COM 			    ((itask->itask_dbufs[i])->db_lu_private)) {
48447836SJohn.Forte@Sun.COM 				stmf_xfer_data_t *xd;
48457836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
48467836SJohn.Forte@Sun.COM 
48477836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
48487836SJohn.Forte@Sun.COM 				xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
48497836SJohn.Forte@Sun.COM 				dbuf->db_lu_private = NULL;
48507836SJohn.Forte@Sun.COM 				kmem_free(xd, xd->alloc_size);
48517836SJohn.Forte@Sun.COM 			}
48527836SJohn.Forte@Sun.COM 			map >>= 1;
48537836SJohn.Forte@Sun.COM 		}
48547836SJohn.Forte@Sun.COM 	}
48557836SJohn.Forte@Sun.COM 	return (STMF_ABORT_SUCCESS);
48567836SJohn.Forte@Sun.COM }
48577836SJohn.Forte@Sun.COM 
48587836SJohn.Forte@Sun.COM void
48597836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task)
48607836SJohn.Forte@Sun.COM {
48617836SJohn.Forte@Sun.COM 	/* Right now we only do this for handling task management functions */
48627836SJohn.Forte@Sun.COM 	ASSERT(task->task_mgmt_function);
48637836SJohn.Forte@Sun.COM 
48647836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
48657836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
48667836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
48677836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
48687836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
48697836SJohn.Forte@Sun.COM 		(void) stmf_lun_reset_poll(task->task_lu, task, 0);
48707836SJohn.Forte@Sun.COM 		return;
48717836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
48727836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
48737836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
48747836SJohn.Forte@Sun.COM 		stmf_target_reset_poll(task);
48757836SJohn.Forte@Sun.COM 		return;
48767836SJohn.Forte@Sun.COM 	}
48777836SJohn.Forte@Sun.COM }
48787836SJohn.Forte@Sun.COM 
48797836SJohn.Forte@Sun.COM /* ARGSUSED */
48807836SJohn.Forte@Sun.COM void
48817836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg)
48827836SJohn.Forte@Sun.COM {
48837836SJohn.Forte@Sun.COM 	/* This function will never be called */
48847836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd);
48857836SJohn.Forte@Sun.COM }
48867836SJohn.Forte@Sun.COM 
48877836SJohn.Forte@Sun.COM void
48887836SJohn.Forte@Sun.COM stmf_dlun_init()
48897836SJohn.Forte@Sun.COM {
48907836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
48917836SJohn.Forte@Sun.COM 
48927836SJohn.Forte@Sun.COM 	dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0);
48937836SJohn.Forte@Sun.COM 	dlun0->lu_task_alloc = stmf_dlun0_task_alloc;
48947836SJohn.Forte@Sun.COM 	dlun0->lu_new_task = stmf_dlun0_new_task;
48957836SJohn.Forte@Sun.COM 	dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done;
48967836SJohn.Forte@Sun.COM 	dlun0->lu_send_status_done = stmf_dlun0_status_done;
48977836SJohn.Forte@Sun.COM 	dlun0->lu_task_free = stmf_dlun0_task_free;
48987836SJohn.Forte@Sun.COM 	dlun0->lu_abort = stmf_dlun0_abort;
48997836SJohn.Forte@Sun.COM 	dlun0->lu_task_poll = stmf_dlun0_task_poll;
49007836SJohn.Forte@Sun.COM 	dlun0->lu_ctl = stmf_dlun0_ctl;
49017836SJohn.Forte@Sun.COM 
49027836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
49037836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
49047836SJohn.Forte@Sun.COM }
49057836SJohn.Forte@Sun.COM 
49067836SJohn.Forte@Sun.COM stmf_status_t
49077836SJohn.Forte@Sun.COM stmf_dlun_fini()
49087836SJohn.Forte@Sun.COM {
49097836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
49107836SJohn.Forte@Sun.COM 
49117836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
49127836SJohn.Forte@Sun.COM 
49137836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
49147836SJohn.Forte@Sun.COM 	if (ilu->ilu_ntasks) {
49157836SJohn.Forte@Sun.COM 		stmf_i_scsi_task_t *itask, *nitask;
49167836SJohn.Forte@Sun.COM 
49177836SJohn.Forte@Sun.COM 		nitask = ilu->ilu_tasks;
49187836SJohn.Forte@Sun.COM 		do {
49197836SJohn.Forte@Sun.COM 			itask = nitask;
49207836SJohn.Forte@Sun.COM 			nitask = itask->itask_lu_next;
49217836SJohn.Forte@Sun.COM 			dlun0->lu_task_free(itask->itask_task);
49227836SJohn.Forte@Sun.COM 			stmf_free(itask->itask_task);
49237836SJohn.Forte@Sun.COM 		} while (nitask != NULL);
49247836SJohn.Forte@Sun.COM 
49257836SJohn.Forte@Sun.COM 	}
49267836SJohn.Forte@Sun.COM 	stmf_free(dlun0);
49277836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
49287836SJohn.Forte@Sun.COM }
49297836SJohn.Forte@Sun.COM 
49307836SJohn.Forte@Sun.COM void
49317836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task)
49327836SJohn.Forte@Sun.COM {
49337836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
49347836SJohn.Forte@Sun.COM 				task->task_session->ss_stmf_private;
49357836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
49367836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
49377836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
49387836SJohn.Forte@Sun.COM 	int i;
49397836SJohn.Forte@Sun.COM 
49407836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
49417836SJohn.Forte@Sun.COM 
49427836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
49437836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
49447836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
49457836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
49467836SJohn.Forte@Sun.COM 			continue;
49477836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
49487836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
49497836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
49507836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
49517836SJohn.Forte@Sun.COM 		}
49527836SJohn.Forte@Sun.COM 	}
49537836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
49547836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
49557836SJohn.Forte@Sun.COM }
49567836SJohn.Forte@Sun.COM 
49577836SJohn.Forte@Sun.COM /*
49587836SJohn.Forte@Sun.COM  * The return value is only used by function managing target reset.
49597836SJohn.Forte@Sun.COM  */
49607836SJohn.Forte@Sun.COM stmf_status_t
49617836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset)
49627836SJohn.Forte@Sun.COM {
49637836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
49647836SJohn.Forte@Sun.COM 	int ntasks_pending;
49657836SJohn.Forte@Sun.COM 
49667836SJohn.Forte@Sun.COM 	ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free;
49677836SJohn.Forte@Sun.COM 	/*
49687836SJohn.Forte@Sun.COM 	 * This function is also used during Target reset. The idea is that
49697836SJohn.Forte@Sun.COM 	 * once all the commands are aborted, call the LU's reset entry
49707836SJohn.Forte@Sun.COM 	 * point (abort entry point with a reset flag). But if this Task
49717836SJohn.Forte@Sun.COM 	 * mgmt is running on this LU then all the tasks cannot be aborted.
49727836SJohn.Forte@Sun.COM 	 * one task (this task) will still be running which is OK.
49737836SJohn.Forte@Sun.COM 	 */
49747836SJohn.Forte@Sun.COM 	if ((ntasks_pending == 0) || ((task->task_lu == lu) &&
49757836SJohn.Forte@Sun.COM 	    (ntasks_pending == 1))) {
49767836SJohn.Forte@Sun.COM 		stmf_status_t ret;
49777836SJohn.Forte@Sun.COM 
49787836SJohn.Forte@Sun.COM 		if ((task->task_mgmt_function == TM_LUN_RESET) ||
49797836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_RESET) ||
49807836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_WARM_RESET) ||
49817836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_COLD_RESET)) {
49827836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0);
49837836SJohn.Forte@Sun.COM 		} else {
49847836SJohn.Forte@Sun.COM 			ret = STMF_SUCCESS;
49857836SJohn.Forte@Sun.COM 		}
49867836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
49877836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
49887836SJohn.Forte@Sun.COM 		}
49897836SJohn.Forte@Sun.COM 		if (target_reset) {
49907836SJohn.Forte@Sun.COM 			return (ret);
49917836SJohn.Forte@Sun.COM 		}
49927836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
49937836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
49947836SJohn.Forte@Sun.COM 			return (ret);
49957836SJohn.Forte@Sun.COM 		}
49967836SJohn.Forte@Sun.COM 		if (ret != STMF_BUSY) {
49977836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL);
49987836SJohn.Forte@Sun.COM 			return (ret);
49997836SJohn.Forte@Sun.COM 		}
50007836SJohn.Forte@Sun.COM 	}
50017836SJohn.Forte@Sun.COM 
50027836SJohn.Forte@Sun.COM 	if (target_reset) {
50037836SJohn.Forte@Sun.COM 		/* Tell target reset polling code that we are not done */
50047836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
50057836SJohn.Forte@Sun.COM 	}
50067836SJohn.Forte@Sun.COM 
50077836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
50087836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
50097836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
50107836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
50117836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
50127836SJohn.Forte@Sun.COM 	}
50137836SJohn.Forte@Sun.COM 
50147836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
50157836SJohn.Forte@Sun.COM }
50167836SJohn.Forte@Sun.COM 
50177836SJohn.Forte@Sun.COM void
50187836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task)
50197836SJohn.Forte@Sun.COM {
50207836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
50217836SJohn.Forte@Sun.COM 				task->task_session->ss_stmf_private;
50227836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
50237836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
50247836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
50257836SJohn.Forte@Sun.COM 	stmf_status_t ret;
50267836SJohn.Forte@Sun.COM 	int i;
50277836SJohn.Forte@Sun.COM 	int not_done = 0;
50287836SJohn.Forte@Sun.COM 
50297836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
50307836SJohn.Forte@Sun.COM 
50317836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
50327836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
50337836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
50347836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
50357836SJohn.Forte@Sun.COM 			continue;
50367836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
50377836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
50387836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
50397836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
50407836SJohn.Forte@Sun.COM 			ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1);
50417836SJohn.Forte@Sun.COM 			rw_enter(iss->iss_lockp, RW_READER);
50427836SJohn.Forte@Sun.COM 			if (ret == STMF_SUCCESS)
50437836SJohn.Forte@Sun.COM 				continue;
50447836SJohn.Forte@Sun.COM 			not_done = 1;
50457836SJohn.Forte@Sun.COM 			if (ret != STMF_BUSY) {
50467836SJohn.Forte@Sun.COM 				rw_exit(iss->iss_lockp);
50477836SJohn.Forte@Sun.COM 				stmf_abort(STMF_QUEUE_TASK_ABORT, task,
50487836SJohn.Forte@Sun.COM 				    STMF_ABORTED, NULL);
50497836SJohn.Forte@Sun.COM 				return;
50507836SJohn.Forte@Sun.COM 			}
50517836SJohn.Forte@Sun.COM 		}
50527836SJohn.Forte@Sun.COM 	}
50537836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
50547836SJohn.Forte@Sun.COM 
50557836SJohn.Forte@Sun.COM 	if (not_done) {
50567836SJohn.Forte@Sun.COM 		if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
50577836SJohn.Forte@Sun.COM 		    != STMF_SUCCESS) {
50587836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
50597836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
50607836SJohn.Forte@Sun.COM 			return;
50617836SJohn.Forte@Sun.COM 		}
50627836SJohn.Forte@Sun.COM 		return;
50637836SJohn.Forte@Sun.COM 	}
50647836SJohn.Forte@Sun.COM 
50657836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
50667836SJohn.Forte@Sun.COM 
50677836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
50687836SJohn.Forte@Sun.COM }
50697836SJohn.Forte@Sun.COM 
50707836SJohn.Forte@Sun.COM stmf_status_t
50717836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid)
50727836SJohn.Forte@Sun.COM {
50737836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
50747836SJohn.Forte@Sun.COM 
50757836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
50767836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
50777836SJohn.Forte@Sun.COM 	}
50787836SJohn.Forte@Sun.COM 
50797836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid);
50807836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
50817836SJohn.Forte@Sun.COM }
50827836SJohn.Forte@Sun.COM 
50837836SJohn.Forte@Sun.COM stmf_status_t
50847836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid)
50857836SJohn.Forte@Sun.COM {
50867836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
50877836SJohn.Forte@Sun.COM 
50887836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
50897836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl);
50907836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
50917836SJohn.Forte@Sun.COM 	}
50927836SJohn.Forte@Sun.COM 
50937836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
50947836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
50957836SJohn.Forte@Sun.COM 	}
50967836SJohn.Forte@Sun.COM 
50977836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid);
50987836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
50997836SJohn.Forte@Sun.COM }
51007836SJohn.Forte@Sun.COM 
51017836SJohn.Forte@Sun.COM stmf_status_t
51027836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid)
51037836SJohn.Forte@Sun.COM {
51047836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
51057836SJohn.Forte@Sun.COM 		(stmf_i_local_port_t *)lport->lport_stmf_private;
51067836SJohn.Forte@Sun.COM 
51077836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
51087836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
51097836SJohn.Forte@Sun.COM 	}
51107836SJohn.Forte@Sun.COM 
51117836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid);
51127836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
51137836SJohn.Forte@Sun.COM }
51147836SJohn.Forte@Sun.COM 
51157836SJohn.Forte@Sun.COM stmf_status_t
51167836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid)
51177836SJohn.Forte@Sun.COM {
51187836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
51197836SJohn.Forte@Sun.COM 		(stmf_i_local_port_t *)lport->lport_stmf_private;
51207836SJohn.Forte@Sun.COM 
51217836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
51227836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl);
51237836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
51247836SJohn.Forte@Sun.COM 	}
51257836SJohn.Forte@Sun.COM 
51267836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
51277836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
51287836SJohn.Forte@Sun.COM 	}
51297836SJohn.Forte@Sun.COM 
51307836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid);
51317836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
51327836SJohn.Forte@Sun.COM }
51337836SJohn.Forte@Sun.COM 
51347836SJohn.Forte@Sun.COM void
51357836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags)
51367836SJohn.Forte@Sun.COM {
51377836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) &&
51387836SJohn.Forte@Sun.COM 	    (ilu->ilu_lu->lu_event_handler != NULL)) {
51397836SJohn.Forte@Sun.COM 		ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags);
51407836SJohn.Forte@Sun.COM 	}
51417836SJohn.Forte@Sun.COM }
51427836SJohn.Forte@Sun.COM 
51437836SJohn.Forte@Sun.COM void
51447836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg,
51457836SJohn.Forte@Sun.COM 				uint32_t flags)
51467836SJohn.Forte@Sun.COM {
51477836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) &&
51487836SJohn.Forte@Sun.COM 	    (ilport->ilport_lport->lport_event_handler != NULL)) {
51497836SJohn.Forte@Sun.COM 		ilport->ilport_lport->lport_event_handler(
51507836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, eventid, arg, flags);
51517836SJohn.Forte@Sun.COM 	}
51527836SJohn.Forte@Sun.COM }
51537836SJohn.Forte@Sun.COM 
51547836SJohn.Forte@Sun.COM void
51557836SJohn.Forte@Sun.COM stmf_svc_init()
51567836SJohn.Forte@Sun.COM {
51577836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
51587836SJohn.Forte@Sun.COM 		return;
51597836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1,
51607836SJohn.Forte@Sun.COM 	    TASKQ_DEFAULTPRI, 0);
51617836SJohn.Forte@Sun.COM 	(void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq,
51627836SJohn.Forte@Sun.COM 	    stmf_svc, 0, DDI_SLEEP);
51637836SJohn.Forte@Sun.COM }
51647836SJohn.Forte@Sun.COM 
51657836SJohn.Forte@Sun.COM stmf_status_t
51667836SJohn.Forte@Sun.COM stmf_svc_fini()
51677836SJohn.Forte@Sun.COM {
51687836SJohn.Forte@Sun.COM 	uint32_t i;
51697836SJohn.Forte@Sun.COM 
51707836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
51717836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) {
51727836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE;
51737836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
51747836SJohn.Forte@Sun.COM 	}
51757836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
51767836SJohn.Forte@Sun.COM 
51777836SJohn.Forte@Sun.COM 	/* Wait for 5 seconds */
51787836SJohn.Forte@Sun.COM 	for (i = 0; i < 500; i++) {
51797836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
51807836SJohn.Forte@Sun.COM 			delay(drv_usectohz(10000));
51817836SJohn.Forte@Sun.COM 		else
51827836SJohn.Forte@Sun.COM 			break;
51837836SJohn.Forte@Sun.COM 	}
51847836SJohn.Forte@Sun.COM 	if (i == 500)
51857836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
51867836SJohn.Forte@Sun.COM 
51877836SJohn.Forte@Sun.COM 	ddi_taskq_destroy(stmf_state.stmf_svc_taskq);
51887836SJohn.Forte@Sun.COM 
51897836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
51907836SJohn.Forte@Sun.COM }
51917836SJohn.Forte@Sun.COM 
51927836SJohn.Forte@Sun.COM /* ARGSUSED */
51937836SJohn.Forte@Sun.COM void
51947836SJohn.Forte@Sun.COM stmf_svc(void *arg)
51957836SJohn.Forte@Sun.COM {
51967836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req, **preq;
51977836SJohn.Forte@Sun.COM 	clock_t td;
51987836SJohn.Forte@Sun.COM 	clock_t	drain_start, drain_next = 0;
51997836SJohn.Forte@Sun.COM 	clock_t	timing_start, timing_next = 0;
52007836SJohn.Forte@Sun.COM 	clock_t worker_delay = 0;
52017836SJohn.Forte@Sun.COM 	int deq;
52027836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
52037836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
52047836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport;
52057836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport, *next_ilport;
52067836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
52077836SJohn.Forte@Sun.COM 
52087836SJohn.Forte@Sun.COM 	td = drv_usectohz(20000);
52097836SJohn.Forte@Sun.COM 
52107836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
52117836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE;
52127836SJohn.Forte@Sun.COM 
52137836SJohn.Forte@Sun.COM stmf_svc_loop:
52147836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) {
52157836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &=
52167836SJohn.Forte@Sun.COM 		    ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE);
52177836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
52187836SJohn.Forte@Sun.COM 		return;
52197836SJohn.Forte@Sun.COM 	}
52207836SJohn.Forte@Sun.COM 
52217836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active) {
52227836SJohn.Forte@Sun.COM 		int waitq_add = 0;
52237836SJohn.Forte@Sun.COM 		req = stmf_state.stmf_svc_active;
52247836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_active = req->svc_next;
52257836SJohn.Forte@Sun.COM 
52267836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
52277836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
52287836SJohn.Forte@Sun.COM 			/* Fallthrough */
52297836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
52307836SJohn.Forte@Sun.COM 			/* Fallthrough */
52317836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
52327836SJohn.Forte@Sun.COM 			/* Nothing to do */
52337836SJohn.Forte@Sun.COM 			waitq_add = 1;
52347836SJohn.Forte@Sun.COM 			break;
52357836SJohn.Forte@Sun.COM 
52367836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
52377836SJohn.Forte@Sun.COM 			/* Remove all mappings of this LU */
52387836SJohn.Forte@Sun.COM 			stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj);
52397836SJohn.Forte@Sun.COM 			/* Kill all the pending I/Os for this LU */
52407836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
52417836SJohn.Forte@Sun.COM 			stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL,
52427836SJohn.Forte@Sun.COM 				STMF_ABORTED);
52437836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
52447836SJohn.Forte@Sun.COM 			waitq_add = 1;
52457836SJohn.Forte@Sun.COM 			break;
52467836SJohn.Forte@Sun.COM 		default:
52477836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d",
52487836SJohn.Forte@Sun.COM 			    req->svc_cmd);
52497836SJohn.Forte@Sun.COM 		}
52507836SJohn.Forte@Sun.COM 
52517836SJohn.Forte@Sun.COM 		if (waitq_add) {
52527836SJohn.Forte@Sun.COM 			/* Put it in the wait queue */
52537836SJohn.Forte@Sun.COM 			req->svc_next = stmf_state.stmf_svc_waiting;
52547836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_waiting = req;
52557836SJohn.Forte@Sun.COM 		}
52567836SJohn.Forte@Sun.COM 	}
52577836SJohn.Forte@Sun.COM 
52587836SJohn.Forte@Sun.COM 	/* The waiting list is not going to be modified by anybody else */
52597836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
52607836SJohn.Forte@Sun.COM 
52617836SJohn.Forte@Sun.COM 	for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) {
52627836SJohn.Forte@Sun.COM 		req = *preq;
52637836SJohn.Forte@Sun.COM 		deq = 0;
52647836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
52657836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
52667836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
52677836SJohn.Forte@Sun.COM 			deq = 1;
52687836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
52697836SJohn.Forte@Sun.COM 			break;
52707836SJohn.Forte@Sun.COM 
52717836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
52727836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
52737836SJohn.Forte@Sun.COM 			ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
52747836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
52757836SJohn.Forte@Sun.COM 				break;
52767836SJohn.Forte@Sun.COM 			deq = 1;
52777836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
52787836SJohn.Forte@Sun.COM 			break;
52797836SJohn.Forte@Sun.COM 
52807836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
52817836SJohn.Forte@Sun.COM 			/* Fallthrough */
52827836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
52837836SJohn.Forte@Sun.COM 			lport = (stmf_local_port_t *)req->svc_obj;
52847836SJohn.Forte@Sun.COM 			deq = 1;
52857836SJohn.Forte@Sun.COM 			lport->lport_ctl(lport, req->svc_cmd, &req->svc_info);
52867836SJohn.Forte@Sun.COM 			break;
52877836SJohn.Forte@Sun.COM 		}
52887836SJohn.Forte@Sun.COM 		if (deq) {
52897836SJohn.Forte@Sun.COM 			*preq = req->svc_next;
52907836SJohn.Forte@Sun.COM 			kmem_free(req, req->svc_req_alloc_size);
52917836SJohn.Forte@Sun.COM 		} else {
52927836SJohn.Forte@Sun.COM 			preq = &req->svc_next;
52937836SJohn.Forte@Sun.COM 		}
52947836SJohn.Forte@Sun.COM 	}
52957836SJohn.Forte@Sun.COM 
52967836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
52977836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active == NULL) {
52987836SJohn.Forte@Sun.COM 		/* Do timeouts */
52997836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
53007836SJohn.Forte@Sun.COM 		    ((!timing_next) || (ddi_get_lbolt() >= timing_next))) {
53017836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
53027836SJohn.Forte@Sun.COM 				/* we are starting a new round */
53037836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_timing =
53047836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
53057836SJohn.Forte@Sun.COM 				timing_start = ddi_get_lbolt();
53067836SJohn.Forte@Sun.COM 			}
53077836SJohn.Forte@Sun.COM 			stmf_check_ilu_timing();
53087836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
53097836SJohn.Forte@Sun.COM 				/* we finished a complete round */
53107836SJohn.Forte@Sun.COM 				timing_next =
53117836SJohn.Forte@Sun.COM 				    timing_start + drv_usectohz(5*1000*1000);
53127836SJohn.Forte@Sun.COM 			} else {
53137836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
53147836SJohn.Forte@Sun.COM 				timing_next =
53157836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
53167836SJohn.Forte@Sun.COM 			}
53177836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
53187836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
53197836SJohn.Forte@Sun.COM 		}
53207836SJohn.Forte@Sun.COM 		/* Check if there are free tasks to clear */
53217836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
53227836SJohn.Forte@Sun.COM 		    ((!drain_next) || (ddi_get_lbolt() >= drain_next))) {
53237836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
53247836SJohn.Forte@Sun.COM 				/* we are starting a new round */
53257836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_draining =
53267836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
53277836SJohn.Forte@Sun.COM 				drain_start = ddi_get_lbolt();
53287836SJohn.Forte@Sun.COM 			}
53297836SJohn.Forte@Sun.COM 			stmf_check_freetask();
53307836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
53317836SJohn.Forte@Sun.COM 				/* we finished a complete round */
53327836SJohn.Forte@Sun.COM 				drain_next =
53337836SJohn.Forte@Sun.COM 				    drain_start + drv_usectohz(10*1000*1000);
53347836SJohn.Forte@Sun.COM 			} else {
53357836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
53367836SJohn.Forte@Sun.COM 				drain_next =
53377836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
53387836SJohn.Forte@Sun.COM 			}
53397836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
53407836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
53417836SJohn.Forte@Sun.COM 		}
53427836SJohn.Forte@Sun.COM 
53437836SJohn.Forte@Sun.COM 		/* Check if we need to run worker_mgmt */
53447836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > worker_delay) {
53457836SJohn.Forte@Sun.COM 			stmf_worker_mgmt();
53467836SJohn.Forte@Sun.COM 			worker_delay = ddi_get_lbolt() +
53477836SJohn.Forte@Sun.COM 			    stmf_worker_mgmt_delay;
53487836SJohn.Forte@Sun.COM 		}
53497836SJohn.Forte@Sun.COM 
53507836SJohn.Forte@Sun.COM 		/* Check if any active session got its 1st LUN */
53517836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_process_initial_luns) {
53527836SJohn.Forte@Sun.COM 			int stmf_level = 0;
53537836SJohn.Forte@Sun.COM 			int port_level;
53547836SJohn.Forte@Sun.COM 			for (ilport = stmf_state.stmf_ilportlist; ilport;
53557836SJohn.Forte@Sun.COM 			    ilport = next_ilport) {
53567836SJohn.Forte@Sun.COM 				next_ilport = ilport->ilport_next;
53577836SJohn.Forte@Sun.COM 				if ((ilport->ilport_flags &
53587836SJohn.Forte@Sun.COM 				    ILPORT_SS_GOT_INITIAL_LUNS) == 0) {
53597836SJohn.Forte@Sun.COM 					continue;
53607836SJohn.Forte@Sun.COM 				}
53617836SJohn.Forte@Sun.COM 				port_level = 0;
53627836SJohn.Forte@Sun.COM 				rw_enter(&ilport->ilport_lock, RW_READER);
53637836SJohn.Forte@Sun.COM 				for (iss = ilport->ilport_ss_list; iss;
53647836SJohn.Forte@Sun.COM 				    iss = iss->iss_next) {
53657836SJohn.Forte@Sun.COM 					if ((iss->iss_flags &
53667836SJohn.Forte@Sun.COM 					    ISS_GOT_INITIAL_LUNS) == 0) {
53677836SJohn.Forte@Sun.COM 						continue;
53687836SJohn.Forte@Sun.COM 					}
53697836SJohn.Forte@Sun.COM 					port_level++;
53707836SJohn.Forte@Sun.COM 					stmf_level++;
53717836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
53727836SJohn.Forte@Sun.COM 						~ISS_GOT_INITIAL_LUNS);
53737836SJohn.Forte@Sun.COM 					atomic_or_32(&iss->iss_flags,
53747836SJohn.Forte@Sun.COM 						ISS_EVENT_ACTIVE);
53757836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
53767836SJohn.Forte@Sun.COM 					mutex_exit(&stmf_state.stmf_lock);
53777836SJohn.Forte@Sun.COM 					stmf_generate_lport_event(ilport,
53787836SJohn.Forte@Sun.COM 					    LPORT_EVENT_INITIAL_LUN_MAPPED,
53797836SJohn.Forte@Sun.COM 					    iss->iss_ss, 0);
53807836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
53817836SJohn.Forte@Sun.COM 						~ISS_EVENT_ACTIVE);
53827836SJohn.Forte@Sun.COM 					mutex_enter(&stmf_state.stmf_lock);
53837836SJohn.Forte@Sun.COM 					/*
53847836SJohn.Forte@Sun.COM 					 * scan all the ilports again as the
53857836SJohn.Forte@Sun.COM 					 * ilport list might have changed.
53867836SJohn.Forte@Sun.COM 					 */
53877836SJohn.Forte@Sun.COM 					next_ilport =
53887836SJohn.Forte@Sun.COM 						stmf_state.stmf_ilportlist;
53897836SJohn.Forte@Sun.COM 					break;
53907836SJohn.Forte@Sun.COM 				}
53917836SJohn.Forte@Sun.COM 				if (port_level == 0) {
53927836SJohn.Forte@Sun.COM 					atomic_and_32(&ilport->ilport_flags,
53937836SJohn.Forte@Sun.COM 						~ILPORT_SS_GOT_INITIAL_LUNS);
53947836SJohn.Forte@Sun.COM 				}
53957836SJohn.Forte@Sun.COM 				/* drop the lock if we are holding it. */
53967836SJohn.Forte@Sun.COM 				if (rw_lock_held(&ilport->ilport_lock))
53977836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
53987836SJohn.Forte@Sun.COM 
53997836SJohn.Forte@Sun.COM 				/* Max 4 session at a time */
54007836SJohn.Forte@Sun.COM 				if (stmf_level >= 4) {
54017836SJohn.Forte@Sun.COM 					break;
54027836SJohn.Forte@Sun.COM 				}
54037836SJohn.Forte@Sun.COM 			}
54047836SJohn.Forte@Sun.COM 			if (stmf_level == 0) {
54057836SJohn.Forte@Sun.COM 				stmf_state.stmf_process_initial_luns = 0;
54067836SJohn.Forte@Sun.COM 			}
54077836SJohn.Forte@Sun.COM 		}
54087836SJohn.Forte@Sun.COM 
54097836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE;
54107836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock,
54117836SJohn.Forte@Sun.COM 		    ddi_get_lbolt() + td);
54127836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
54137836SJohn.Forte@Sun.COM 	}
54147836SJohn.Forte@Sun.COM 	goto stmf_svc_loop;
54157836SJohn.Forte@Sun.COM }
54167836SJohn.Forte@Sun.COM 
54177836SJohn.Forte@Sun.COM void
54187836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
54197836SJohn.Forte@Sun.COM {
54207836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req;
54217836SJohn.Forte@Sun.COM 	int s;
54227836SJohn.Forte@Sun.COM 
54237836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&stmf_state.stmf_lock));
54247836SJohn.Forte@Sun.COM 	s = sizeof (stmf_svc_req_t);
54257836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
54267836SJohn.Forte@Sun.COM 		s += strlen(info->st_additional_info) + 1;
54277836SJohn.Forte@Sun.COM 	}
54287836SJohn.Forte@Sun.COM 	req = kmem_zalloc(s, KM_SLEEP);
54297836SJohn.Forte@Sun.COM 
54307836SJohn.Forte@Sun.COM 	req->svc_cmd = cmd;
54317836SJohn.Forte@Sun.COM 	req->svc_obj = obj;
54327836SJohn.Forte@Sun.COM 	req->svc_info.st_rflags = info->st_rflags;
54337836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
54347836SJohn.Forte@Sun.COM 		req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req,
54357836SJohn.Forte@Sun.COM 		    sizeof (stmf_svc_req_t)));
54367836SJohn.Forte@Sun.COM 		(void) strcpy(req->svc_info.st_additional_info,
54377836SJohn.Forte@Sun.COM 		    info->st_additional_info);
54387836SJohn.Forte@Sun.COM 	}
54397836SJohn.Forte@Sun.COM 	req->svc_req_alloc_size = s;
54407836SJohn.Forte@Sun.COM 
54417836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
54427836SJohn.Forte@Sun.COM 	req->svc_next = stmf_state.stmf_svc_active;
54437836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_active = req;
54447836SJohn.Forte@Sun.COM 	if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) {
54457836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
54467836SJohn.Forte@Sun.COM 	}
54477836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
54487836SJohn.Forte@Sun.COM }
54497836SJohn.Forte@Sun.COM 
54507836SJohn.Forte@Sun.COM void
54517836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...)
54527836SJohn.Forte@Sun.COM {
54537836SJohn.Forte@Sun.COM 	va_list args;
54547836SJohn.Forte@Sun.COM 	char tbuf[160];
54557836SJohn.Forte@Sun.COM 	int len;
54567836SJohn.Forte@Sun.COM 
54577836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
54587836SJohn.Forte@Sun.COM 		return;
54597836SJohn.Forte@Sun.COM 	len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "",
54607836SJohn.Forte@Sun.COM 	    ddi_get_lbolt());
54617836SJohn.Forte@Sun.COM 	va_start(args, fmt);
54627836SJohn.Forte@Sun.COM 	len += vsnprintf(tbuf + len, 158 - len, fmt, args);
54637836SJohn.Forte@Sun.COM 	va_end(args);
54647836SJohn.Forte@Sun.COM 
54657836SJohn.Forte@Sun.COM 	if (len > 158) {
54667836SJohn.Forte@Sun.COM 		len = 158;
54677836SJohn.Forte@Sun.COM 	}
54687836SJohn.Forte@Sun.COM 	tbuf[len++] = '\n';
54697836SJohn.Forte@Sun.COM 	tbuf[len] = 0;
54707836SJohn.Forte@Sun.COM 
54717836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
54727836SJohn.Forte@Sun.COM 	bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1);
54737836SJohn.Forte@Sun.COM 	trace_buf_curndx += len;
54747836SJohn.Forte@Sun.COM 	if (trace_buf_curndx > (trace_buf_size - 320))
54757836SJohn.Forte@Sun.COM 		trace_buf_curndx = 0;
54767836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
54777836SJohn.Forte@Sun.COM }
54787836SJohn.Forte@Sun.COM 
54797836SJohn.Forte@Sun.COM void
54807836SJohn.Forte@Sun.COM stmf_trace_clear()
54817836SJohn.Forte@Sun.COM {
54827836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
54837836SJohn.Forte@Sun.COM 		return;
54847836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
54857836SJohn.Forte@Sun.COM 	trace_buf_curndx = 0;
54867836SJohn.Forte@Sun.COM 	if (trace_buf_size > 0)
54877836SJohn.Forte@Sun.COM 		stmf_trace_buf[0] = 0;
54887836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
54897836SJohn.Forte@Sun.COM }
54907836SJohn.Forte@Sun.COM 
54917836SJohn.Forte@Sun.COM static void
54927836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info)
54937836SJohn.Forte@Sun.COM {
54947836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	 change_info;
54957836SJohn.Forte@Sun.COM 	void				*ctl_private;
54967836SJohn.Forte@Sun.COM 	uint32_t			 ctl_cmd;
54977836SJohn.Forte@Sun.COM 	int				msg = 0;
54987836SJohn.Forte@Sun.COM 
54997836SJohn.Forte@Sun.COM 	stmf_trace("FROM STMF", "abort_task_offline called for %s: %s",
55007836SJohn.Forte@Sun.COM 	    offline_lu ? "LU" : "LPORT", info ? info : "no additional info");
55017836SJohn.Forte@Sun.COM 	change_info.st_additional_info = info;
55027836SJohn.Forte@Sun.COM 	if (offline_lu) {
55037836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
55047836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LU_ABORT;
55057836SJohn.Forte@Sun.COM 		ctl_private = task->task_lu;
55067836SJohn.Forte@Sun.COM 		if (((stmf_i_lu_t *)
55077836SJohn.Forte@Sun.COM 		    task->task_lu->lu_stmf_private)->ilu_state ==
55087836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
55097836SJohn.Forte@Sun.COM 			msg = 1;
55107836SJohn.Forte@Sun.COM 		}
55117836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LU_OFFLINE;
55127836SJohn.Forte@Sun.COM 	} else {
55137836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
55147836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LPORT_ABORT;
55157836SJohn.Forte@Sun.COM 		ctl_private = task->task_lport;
55167836SJohn.Forte@Sun.COM 		if (((stmf_i_local_port_t *)
55177836SJohn.Forte@Sun.COM 		    task->task_lport->lport_stmf_private)->ilport_state ==
55187836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
55197836SJohn.Forte@Sun.COM 			msg = 1;
55207836SJohn.Forte@Sun.COM 		}
55217836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LPORT_OFFLINE;
55227836SJohn.Forte@Sun.COM 	}
55237836SJohn.Forte@Sun.COM 
55247836SJohn.Forte@Sun.COM 	if (msg) {
55257836SJohn.Forte@Sun.COM 		stmf_trace(0, "Calling stmf_ctl to offline %s : %s",
55267836SJohn.Forte@Sun.COM 		    offline_lu ? "LU" : "LPORT", info ? info :
55277836SJohn.Forte@Sun.COM 		    "<no additional info>");
55287836SJohn.Forte@Sun.COM 	}
55297836SJohn.Forte@Sun.COM 	(void) stmf_ctl(ctl_cmd, ctl_private, &change_info);
55307836SJohn.Forte@Sun.COM }
5531