xref: /onnv-gate/usr/src/uts/common/io/comstar/stmf/stmf.c (revision 9962:2b6bca766b65)
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 /*
228662SJordan.Vaughan@Sun.com  * Copyright 2009 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>
398662SJordan.Vaughan@Sun.com #include <sys/zone.h>
407836SJohn.Forte@Sun.COM 
417836SJohn.Forte@Sun.COM #include <stmf.h>
427836SJohn.Forte@Sun.COM #include <lpif.h>
437836SJohn.Forte@Sun.COM #include <portif.h>
447836SJohn.Forte@Sun.COM #include <stmf_ioctl.h>
457836SJohn.Forte@Sun.COM #include <stmf_impl.h>
467836SJohn.Forte@Sun.COM #include <lun_map.h>
477836SJohn.Forte@Sun.COM #include <stmf_state.h>
487836SJohn.Forte@Sun.COM 
497836SJohn.Forte@Sun.COM static uint64_t stmf_session_counter = 0;
507836SJohn.Forte@Sun.COM static uint16_t stmf_rtpid_counter = 0;
517836SJohn.Forte@Sun.COM 
527836SJohn.Forte@Sun.COM static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
537836SJohn.Forte@Sun.COM static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
547836SJohn.Forte@Sun.COM static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
557836SJohn.Forte@Sun.COM 	void **result);
567836SJohn.Forte@Sun.COM static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp);
577836SJohn.Forte@Sun.COM static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp);
587836SJohn.Forte@Sun.COM static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
597836SJohn.Forte@Sun.COM 	cred_t *credp, int *rval);
607836SJohn.Forte@Sun.COM static int stmf_get_stmf_state(stmf_state_desc_t *std);
617836SJohn.Forte@Sun.COM static int stmf_set_stmf_state(stmf_state_desc_t *std);
627836SJohn.Forte@Sun.COM static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu,
637836SJohn.Forte@Sun.COM     char *info);
647836SJohn.Forte@Sun.COM void stmf_svc_init();
657836SJohn.Forte@Sun.COM stmf_status_t stmf_svc_fini();
667836SJohn.Forte@Sun.COM void stmf_svc(void *arg);
677836SJohn.Forte@Sun.COM void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
687836SJohn.Forte@Sun.COM void stmf_check_freetask();
697836SJohn.Forte@Sun.COM void stmf_abort_target_reset(scsi_task_t *task);
707836SJohn.Forte@Sun.COM stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task,
717836SJohn.Forte@Sun.COM 							int target_reset);
727836SJohn.Forte@Sun.COM void stmf_target_reset_poll(struct scsi_task *task);
737836SJohn.Forte@Sun.COM void stmf_handle_lun_reset(scsi_task_t *task);
747836SJohn.Forte@Sun.COM void stmf_handle_target_reset(scsi_task_t *task);
757836SJohn.Forte@Sun.COM void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf);
769585STim.Szeto@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
779585STim.Szeto@Sun.COM     uint32_t *err_ret);
787836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
799585STim.Szeto@Sun.COM int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
809585STim.Szeto@Sun.COM     uint32_t *err_ret);
817836SJohn.Forte@Sun.COM void stmf_delete_ppd(stmf_pp_data_t *ppd);
827836SJohn.Forte@Sun.COM void stmf_delete_all_ppds();
837836SJohn.Forte@Sun.COM void stmf_trace_clear();
847836SJohn.Forte@Sun.COM void stmf_worker_init();
857836SJohn.Forte@Sun.COM stmf_status_t stmf_worker_fini();
867836SJohn.Forte@Sun.COM void stmf_worker_mgmt();
877836SJohn.Forte@Sun.COM void stmf_worker_task(void *arg);
887836SJohn.Forte@Sun.COM 
899435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_q(scsi_task_t *, void());
909435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_q(scsi_task_t *, void());
919435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_io(scsi_task_t *, stmf_data_buf_t *);
929435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_io(scsi_task_t *, stmf_data_buf_t *);
939435STim.Szeto@Sun.COM 
947836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops;
957836SJohn.Forte@Sun.COM 
967836SJohn.Forte@Sun.COM /* =====[ Tunables ]===== */
977836SJohn.Forte@Sun.COM /* Internal tracing */
987836SJohn.Forte@Sun.COM volatile int	stmf_trace_on = 1;
997836SJohn.Forte@Sun.COM volatile int	stmf_trace_buf_size = (1 * 1024 * 1024);
1007836SJohn.Forte@Sun.COM /*
1017836SJohn.Forte@Sun.COM  * The reason default task timeout is 75 is because we want the
1027836SJohn.Forte@Sun.COM  * host to timeout 1st and mostly host timeout is 60 seconds.
1037836SJohn.Forte@Sun.COM  */
1047836SJohn.Forte@Sun.COM volatile int	stmf_default_task_timeout = 75;
1057836SJohn.Forte@Sun.COM /*
1067836SJohn.Forte@Sun.COM  * Setting this to one means, you are responsible for config load and keeping
1077836SJohn.Forte@Sun.COM  * things in sync with persistent database.
1087836SJohn.Forte@Sun.COM  */
1097836SJohn.Forte@Sun.COM volatile int	stmf_allow_modunload = 0;
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM volatile int stmf_max_nworkers = 256;
1127836SJohn.Forte@Sun.COM volatile int stmf_min_nworkers = 4;
1137836SJohn.Forte@Sun.COM volatile int stmf_worker_scale_down_delay = 20;
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM /* === [ Debugging and fault injection ] === */
1167836SJohn.Forte@Sun.COM #ifdef	DEBUG
1177836SJohn.Forte@Sun.COM volatile int stmf_drop_task_counter = 0;
1187836SJohn.Forte@Sun.COM volatile int stmf_drop_buf_counter = 0;
1197836SJohn.Forte@Sun.COM 
1207836SJohn.Forte@Sun.COM #endif
1217836SJohn.Forte@Sun.COM 
1227836SJohn.Forte@Sun.COM stmf_state_t		stmf_state;
1237836SJohn.Forte@Sun.COM static stmf_lu_t	*dlun0;
1247836SJohn.Forte@Sun.COM 
1257836SJohn.Forte@Sun.COM static uint8_t stmf_first_zero[] =
1267836SJohn.Forte@Sun.COM 	{ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
1277836SJohn.Forte@Sun.COM static uint8_t stmf_first_one[] =
1287836SJohn.Forte@Sun.COM 	{ 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
1297836SJohn.Forte@Sun.COM 
1307836SJohn.Forte@Sun.COM static kmutex_t	trace_buf_lock;
1317836SJohn.Forte@Sun.COM static int	trace_buf_size;
1327836SJohn.Forte@Sun.COM static int	trace_buf_curndx;
1337836SJohn.Forte@Sun.COM caddr_t	stmf_trace_buf;
1347836SJohn.Forte@Sun.COM 
1357836SJohn.Forte@Sun.COM static enum {
1367836SJohn.Forte@Sun.COM 	STMF_WORKERS_DISABLED = 0,
1377836SJohn.Forte@Sun.COM 	STMF_WORKERS_ENABLING,
1387836SJohn.Forte@Sun.COM 	STMF_WORKERS_ENABLED
1397836SJohn.Forte@Sun.COM } stmf_workers_state = STMF_WORKERS_DISABLED;
1407836SJohn.Forte@Sun.COM static int stmf_i_max_nworkers;
1417836SJohn.Forte@Sun.COM static int stmf_i_min_nworkers;
1427836SJohn.Forte@Sun.COM static int stmf_nworkers_cur;		/* # of workers currently running */
1437836SJohn.Forte@Sun.COM static int stmf_nworkers_needed;	/* # of workers need to be running */
1447836SJohn.Forte@Sun.COM static int stmf_worker_sel_counter = 0;
1457836SJohn.Forte@Sun.COM static uint32_t stmf_cur_ntasks = 0;
1467836SJohn.Forte@Sun.COM static clock_t stmf_wm_last = 0;
1477836SJohn.Forte@Sun.COM /*
1487836SJohn.Forte@Sun.COM  * This is equal to stmf_nworkers_cur while we are increasing # workers and
1497836SJohn.Forte@Sun.COM  * stmf_nworkers_needed while we are decreasing the worker count.
1507836SJohn.Forte@Sun.COM  */
1517836SJohn.Forte@Sun.COM static int stmf_nworkers_accepting_cmds;
1527836SJohn.Forte@Sun.COM static stmf_worker_t *stmf_workers = NULL;
1537836SJohn.Forte@Sun.COM static clock_t stmf_worker_mgmt_delay = 2;
1547836SJohn.Forte@Sun.COM static clock_t stmf_worker_scale_down_timer = 0;
1557836SJohn.Forte@Sun.COM static int stmf_worker_scale_down_qd = 0;
1567836SJohn.Forte@Sun.COM 
1577836SJohn.Forte@Sun.COM static struct cb_ops stmf_cb_ops = {
1587836SJohn.Forte@Sun.COM 	stmf_open,			/* open */
1597836SJohn.Forte@Sun.COM 	stmf_close,			/* close */
1607836SJohn.Forte@Sun.COM 	nodev,				/* strategy */
1617836SJohn.Forte@Sun.COM 	nodev,				/* print */
1627836SJohn.Forte@Sun.COM 	nodev,				/* dump */
1637836SJohn.Forte@Sun.COM 	nodev,				/* read */
1647836SJohn.Forte@Sun.COM 	nodev,				/* write */
1657836SJohn.Forte@Sun.COM 	stmf_ioctl,			/* ioctl */
1667836SJohn.Forte@Sun.COM 	nodev,				/* devmap */
1677836SJohn.Forte@Sun.COM 	nodev,				/* mmap */
1687836SJohn.Forte@Sun.COM 	nodev,				/* segmap */
1697836SJohn.Forte@Sun.COM 	nochpoll,			/* chpoll */
1707836SJohn.Forte@Sun.COM 	ddi_prop_op,			/* cb_prop_op */
1717836SJohn.Forte@Sun.COM 	0,				/* streamtab */
1727836SJohn.Forte@Sun.COM 	D_NEW | D_MP,			/* cb_flag */
1737836SJohn.Forte@Sun.COM 	CB_REV,				/* rev */
1747836SJohn.Forte@Sun.COM 	nodev,				/* aread */
1757836SJohn.Forte@Sun.COM 	nodev				/* awrite */
1767836SJohn.Forte@Sun.COM };
1777836SJohn.Forte@Sun.COM 
1787836SJohn.Forte@Sun.COM static struct dev_ops stmf_ops = {
1797836SJohn.Forte@Sun.COM 	DEVO_REV,
1807836SJohn.Forte@Sun.COM 	0,
1817836SJohn.Forte@Sun.COM 	stmf_getinfo,
1827836SJohn.Forte@Sun.COM 	nulldev,		/* identify */
1837836SJohn.Forte@Sun.COM 	nulldev,		/* probe */
1847836SJohn.Forte@Sun.COM 	stmf_attach,
1857836SJohn.Forte@Sun.COM 	stmf_detach,
1867836SJohn.Forte@Sun.COM 	nodev,			/* reset */
1877836SJohn.Forte@Sun.COM 	&stmf_cb_ops,
1887836SJohn.Forte@Sun.COM 	NULL,			/* bus_ops */
1897836SJohn.Forte@Sun.COM 	NULL			/* power */
1907836SJohn.Forte@Sun.COM };
1917836SJohn.Forte@Sun.COM 
1929435STim.Szeto@Sun.COM #define	STMF_NAME		"COMSTAR STMF"
1939435STim.Szeto@Sun.COM #define	STMF_MODULE_NAME	"stmf"
1947836SJohn.Forte@Sun.COM 
1957836SJohn.Forte@Sun.COM static struct modldrv modldrv = {
1967836SJohn.Forte@Sun.COM 	&mod_driverops,
1977836SJohn.Forte@Sun.COM 	STMF_NAME,
1987836SJohn.Forte@Sun.COM 	&stmf_ops
1997836SJohn.Forte@Sun.COM };
2007836SJohn.Forte@Sun.COM 
2017836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
2027836SJohn.Forte@Sun.COM 	MODREV_1,
2037836SJohn.Forte@Sun.COM 	&modldrv,
2047836SJohn.Forte@Sun.COM 	NULL
2057836SJohn.Forte@Sun.COM };
2067836SJohn.Forte@Sun.COM 
2077836SJohn.Forte@Sun.COM int
2087836SJohn.Forte@Sun.COM _init(void)
2097836SJohn.Forte@Sun.COM {
2107836SJohn.Forte@Sun.COM 	int ret;
2117836SJohn.Forte@Sun.COM 
2127836SJohn.Forte@Sun.COM 	ret = mod_install(&modlinkage);
2137836SJohn.Forte@Sun.COM 	if (ret)
2147836SJohn.Forte@Sun.COM 		return (ret);
2157836SJohn.Forte@Sun.COM 	stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP);
2167836SJohn.Forte@Sun.COM 	trace_buf_size = stmf_trace_buf_size;
2177836SJohn.Forte@Sun.COM 	trace_buf_curndx = 0;
2187836SJohn.Forte@Sun.COM 	mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0);
2197836SJohn.Forte@Sun.COM 	bzero(&stmf_state, sizeof (stmf_state_t));
2207836SJohn.Forte@Sun.COM 	/* STMF service is off by default */
2217836SJohn.Forte@Sun.COM 	stmf_state.stmf_service_running = 0;
2227836SJohn.Forte@Sun.COM 	mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL);
2237836SJohn.Forte@Sun.COM 	cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL);
2247836SJohn.Forte@Sun.COM 	stmf_session_counter = (uint64_t)ddi_get_lbolt();
2257836SJohn.Forte@Sun.COM 	stmf_view_init();
2267836SJohn.Forte@Sun.COM 	stmf_svc_init();
2277836SJohn.Forte@Sun.COM 	stmf_dlun_init();
2287836SJohn.Forte@Sun.COM 	return (ret);
2297836SJohn.Forte@Sun.COM }
2307836SJohn.Forte@Sun.COM 
2317836SJohn.Forte@Sun.COM int
2327836SJohn.Forte@Sun.COM _fini(void)
2337836SJohn.Forte@Sun.COM {
2347836SJohn.Forte@Sun.COM 	int ret;
2357836SJohn.Forte@Sun.COM 
2367836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running)
2377836SJohn.Forte@Sun.COM 		return (EBUSY);
2387836SJohn.Forte@Sun.COM 	if ((!stmf_allow_modunload) &&
2397836SJohn.Forte@Sun.COM 	    (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) {
2407836SJohn.Forte@Sun.COM 		return (EBUSY);
2417836SJohn.Forte@Sun.COM 	}
2427836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_nlps || stmf_state.stmf_npps) {
2437836SJohn.Forte@Sun.COM 		return (EBUSY);
2447836SJohn.Forte@Sun.COM 	}
2457836SJohn.Forte@Sun.COM 	if (stmf_dlun_fini() != STMF_SUCCESS)
2467836SJohn.Forte@Sun.COM 		return (EBUSY);
2477836SJohn.Forte@Sun.COM 	if (stmf_worker_fini() != STMF_SUCCESS) {
2487836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2497836SJohn.Forte@Sun.COM 		return (EBUSY);
2507836SJohn.Forte@Sun.COM 	}
2517836SJohn.Forte@Sun.COM 	if (stmf_svc_fini() != STMF_SUCCESS) {
2527836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2537836SJohn.Forte@Sun.COM 		stmf_worker_init();
2547836SJohn.Forte@Sun.COM 		return (EBUSY);
2557836SJohn.Forte@Sun.COM 	}
2567836SJohn.Forte@Sun.COM 
2577836SJohn.Forte@Sun.COM 	ret = mod_remove(&modlinkage);
2587836SJohn.Forte@Sun.COM 	if (ret) {
2597836SJohn.Forte@Sun.COM 		stmf_svc_init();
2607836SJohn.Forte@Sun.COM 		stmf_dlun_init();
2617836SJohn.Forte@Sun.COM 		stmf_worker_init();
2627836SJohn.Forte@Sun.COM 		return (ret);
2637836SJohn.Forte@Sun.COM 	}
2647836SJohn.Forte@Sun.COM 
2657836SJohn.Forte@Sun.COM 	stmf_view_clear_config();
2667836SJohn.Forte@Sun.COM 	kmem_free(stmf_trace_buf, stmf_trace_buf_size);
2677836SJohn.Forte@Sun.COM 	mutex_destroy(&trace_buf_lock);
2687836SJohn.Forte@Sun.COM 	mutex_destroy(&stmf_state.stmf_lock);
2697836SJohn.Forte@Sun.COM 	cv_destroy(&stmf_state.stmf_cv);
2707836SJohn.Forte@Sun.COM 	return (ret);
2717836SJohn.Forte@Sun.COM }
2727836SJohn.Forte@Sun.COM 
2737836SJohn.Forte@Sun.COM int
2747836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
2757836SJohn.Forte@Sun.COM {
2767836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
2777836SJohn.Forte@Sun.COM }
2787836SJohn.Forte@Sun.COM 
2797836SJohn.Forte@Sun.COM /* ARGSUSED */
2807836SJohn.Forte@Sun.COM static int
2817836SJohn.Forte@Sun.COM stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2827836SJohn.Forte@Sun.COM {
2837836SJohn.Forte@Sun.COM 	switch (cmd) {
2847836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
2857836SJohn.Forte@Sun.COM 		*result = stmf_state.stmf_dip;
2867836SJohn.Forte@Sun.COM 		break;
2877836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
2889585STim.Szeto@Sun.COM 		*result =
2899585STim.Szeto@Sun.COM 		    (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip);
2907836SJohn.Forte@Sun.COM 		break;
2917836SJohn.Forte@Sun.COM 	default:
2927836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
2937836SJohn.Forte@Sun.COM 	}
2947836SJohn.Forte@Sun.COM 
2957836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
2967836SJohn.Forte@Sun.COM }
2977836SJohn.Forte@Sun.COM 
2987836SJohn.Forte@Sun.COM static int
2997836SJohn.Forte@Sun.COM stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3007836SJohn.Forte@Sun.COM {
3017836SJohn.Forte@Sun.COM 	switch (cmd) {
3027836SJohn.Forte@Sun.COM 	case DDI_ATTACH:
3037836SJohn.Forte@Sun.COM 		stmf_state.stmf_dip = dip;
3047836SJohn.Forte@Sun.COM 
3057836SJohn.Forte@Sun.COM 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
3067836SJohn.Forte@Sun.COM 		    DDI_NT_STMF, 0) != DDI_SUCCESS) {
3077836SJohn.Forte@Sun.COM 			break;
3087836SJohn.Forte@Sun.COM 		}
3097836SJohn.Forte@Sun.COM 		ddi_report_dev(dip);
3107836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
3117836SJohn.Forte@Sun.COM 	}
3127836SJohn.Forte@Sun.COM 
3137836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
3147836SJohn.Forte@Sun.COM }
3157836SJohn.Forte@Sun.COM 
3167836SJohn.Forte@Sun.COM static int
3177836SJohn.Forte@Sun.COM stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3187836SJohn.Forte@Sun.COM {
3197836SJohn.Forte@Sun.COM 	switch (cmd) {
3207836SJohn.Forte@Sun.COM 	case DDI_DETACH:
3217836SJohn.Forte@Sun.COM 		ddi_remove_minor_node(dip, 0);
3227836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
3237836SJohn.Forte@Sun.COM 	}
3247836SJohn.Forte@Sun.COM 
3257836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
3267836SJohn.Forte@Sun.COM }
3277836SJohn.Forte@Sun.COM 
3287836SJohn.Forte@Sun.COM /* ARGSUSED */
3297836SJohn.Forte@Sun.COM static int
3307836SJohn.Forte@Sun.COM stmf_open(dev_t *devp, int flag, int otype, cred_t *credp)
3317836SJohn.Forte@Sun.COM {
3327836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
3337836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_exclusive_open) {
3347836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
3357836SJohn.Forte@Sun.COM 		return (EBUSY);
3367836SJohn.Forte@Sun.COM 	}
3377836SJohn.Forte@Sun.COM 	if (flag & FEXCL) {
3387836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_opened) {
3397836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
3407836SJohn.Forte@Sun.COM 			return (EBUSY);
3417836SJohn.Forte@Sun.COM 		}
3427836SJohn.Forte@Sun.COM 		stmf_state.stmf_exclusive_open = 1;
3437836SJohn.Forte@Sun.COM 	}
3447836SJohn.Forte@Sun.COM 	stmf_state.stmf_opened = 1;
3457836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
3467836SJohn.Forte@Sun.COM 	return (0);
3477836SJohn.Forte@Sun.COM }
3487836SJohn.Forte@Sun.COM 
3497836SJohn.Forte@Sun.COM /* ARGSUSED */
3507836SJohn.Forte@Sun.COM static int
3517836SJohn.Forte@Sun.COM stmf_close(dev_t dev, int flag, int otype, cred_t *credp)
3527836SJohn.Forte@Sun.COM {
3537836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
3547836SJohn.Forte@Sun.COM 	stmf_state.stmf_opened = 0;
3557836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_exclusive_open &&
3567836SJohn.Forte@Sun.COM 	    (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) {
3577836SJohn.Forte@Sun.COM 		stmf_state.stmf_config_state = STMF_CONFIG_NONE;
3587836SJohn.Forte@Sun.COM 		stmf_delete_all_ppds();
3597836SJohn.Forte@Sun.COM 		stmf_view_clear_config();
3607836SJohn.Forte@Sun.COM 		stmf_view_init();
3617836SJohn.Forte@Sun.COM 	}
3627836SJohn.Forte@Sun.COM 	stmf_state.stmf_exclusive_open = 0;
3637836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
3647836SJohn.Forte@Sun.COM 	return (0);
3657836SJohn.Forte@Sun.COM }
3667836SJohn.Forte@Sun.COM 
3677836SJohn.Forte@Sun.COM int
3687836SJohn.Forte@Sun.COM stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd,
3697836SJohn.Forte@Sun.COM 						void **ibuf, void **obuf)
3707836SJohn.Forte@Sun.COM {
3717836SJohn.Forte@Sun.COM 	int ret;
3727836SJohn.Forte@Sun.COM 
3737836SJohn.Forte@Sun.COM 	*ibuf = NULL;
3747836SJohn.Forte@Sun.COM 	*obuf = NULL;
3757836SJohn.Forte@Sun.COM 	*iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP);
3767836SJohn.Forte@Sun.COM 
3777836SJohn.Forte@Sun.COM 	ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode);
3787836SJohn.Forte@Sun.COM 	if (ret)
3797836SJohn.Forte@Sun.COM 		return (EFAULT);
3807836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_version != STMF_VERSION_1) {
3817836SJohn.Forte@Sun.COM 		ret = EINVAL;
3827836SJohn.Forte@Sun.COM 		goto copyin_iocdata_done;
3837836SJohn.Forte@Sun.COM 	}
3847836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_ibuf_size) {
3857836SJohn.Forte@Sun.COM 		*ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP);
3867836SJohn.Forte@Sun.COM 		ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf),
3877836SJohn.Forte@Sun.COM 		    *ibuf, (*iocd)->stmf_ibuf_size, mode);
3887836SJohn.Forte@Sun.COM 	}
3897836SJohn.Forte@Sun.COM 	if ((*iocd)->stmf_obuf_size)
3907836SJohn.Forte@Sun.COM 		*obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP);
3917836SJohn.Forte@Sun.COM 
3927836SJohn.Forte@Sun.COM 	if (ret == 0)
3937836SJohn.Forte@Sun.COM 		return (0);
3947836SJohn.Forte@Sun.COM 	ret = EFAULT;
3957836SJohn.Forte@Sun.COM copyin_iocdata_done:;
3967836SJohn.Forte@Sun.COM 	if (*obuf) {
3977836SJohn.Forte@Sun.COM 		kmem_free(*obuf, (*iocd)->stmf_obuf_size);
3987836SJohn.Forte@Sun.COM 		*obuf = NULL;
3997836SJohn.Forte@Sun.COM 	}
4007836SJohn.Forte@Sun.COM 	if (*ibuf) {
4017836SJohn.Forte@Sun.COM 		kmem_free(*ibuf, (*iocd)->stmf_ibuf_size);
4027836SJohn.Forte@Sun.COM 		*ibuf = NULL;
4037836SJohn.Forte@Sun.COM 	}
4047836SJohn.Forte@Sun.COM 	kmem_free(*iocd, sizeof (stmf_iocdata_t));
4057836SJohn.Forte@Sun.COM 	return (ret);
4067836SJohn.Forte@Sun.COM }
4077836SJohn.Forte@Sun.COM 
4087836SJohn.Forte@Sun.COM int
4097836SJohn.Forte@Sun.COM stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf)
4107836SJohn.Forte@Sun.COM {
4117836SJohn.Forte@Sun.COM 	int ret;
4127836SJohn.Forte@Sun.COM 
4137836SJohn.Forte@Sun.COM 	if (iocd->stmf_obuf_size) {
4147836SJohn.Forte@Sun.COM 		ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf,
4157836SJohn.Forte@Sun.COM 		    iocd->stmf_obuf_size, mode);
4167836SJohn.Forte@Sun.COM 		if (ret)
4177836SJohn.Forte@Sun.COM 			return (EFAULT);
4187836SJohn.Forte@Sun.COM 	}
4197836SJohn.Forte@Sun.COM 	ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode);
4207836SJohn.Forte@Sun.COM 	if (ret)
4217836SJohn.Forte@Sun.COM 		return (EFAULT);
4227836SJohn.Forte@Sun.COM 	return (0);
4237836SJohn.Forte@Sun.COM }
4247836SJohn.Forte@Sun.COM 
4257836SJohn.Forte@Sun.COM /* ARGSUSED */
4267836SJohn.Forte@Sun.COM static int
4277836SJohn.Forte@Sun.COM stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
4287836SJohn.Forte@Sun.COM 	cred_t *credp, int *rval)
4297836SJohn.Forte@Sun.COM {
4307836SJohn.Forte@Sun.COM 	stmf_iocdata_t *iocd;
4317836SJohn.Forte@Sun.COM 	void *ibuf = NULL, *obuf = NULL;
4327836SJohn.Forte@Sun.COM 	slist_lu_t *luid_list;
4337836SJohn.Forte@Sun.COM 	slist_target_port_t *lportid_list;
4347836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
4357836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
4367836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
4377836SJohn.Forte@Sun.COM 	slist_scsi_session_t *iss_list;
4387836SJohn.Forte@Sun.COM 	sioc_lu_props_t *lup;
4397836SJohn.Forte@Sun.COM 	sioc_target_port_props_t *lportp;
4409585STim.Szeto@Sun.COM 	stmf_ppioctl_data_t *ppi, *ppi_out = NULL;
4419585STim.Szeto@Sun.COM 	uint64_t *ppi_token = NULL;
4429585STim.Szeto@Sun.COM 	uint8_t *p_id, *id;
4437836SJohn.Forte@Sun.COM 	stmf_state_desc_t *std;
4447836SJohn.Forte@Sun.COM 	stmf_status_t ctl_ret;
4457836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssi;
4467836SJohn.Forte@Sun.COM 	int ret = 0;
4477836SJohn.Forte@Sun.COM 	uint32_t n;
4487836SJohn.Forte@Sun.COM 	int i;
4497836SJohn.Forte@Sun.COM 	stmf_group_op_data_t *grp_entry;
4507836SJohn.Forte@Sun.COM 	stmf_group_name_t *grpname;
4517836SJohn.Forte@Sun.COM 	stmf_view_op_entry_t *ve;
4527836SJohn.Forte@Sun.COM 	stmf_id_type_t idtype;
4537836SJohn.Forte@Sun.COM 	stmf_id_data_t *id_entry;
4547836SJohn.Forte@Sun.COM 	stmf_id_list_t	*id_list;
4557836SJohn.Forte@Sun.COM 	stmf_view_entry_t *view_entry;
4567836SJohn.Forte@Sun.COM 	uint32_t	veid;
4577836SJohn.Forte@Sun.COM 
4587836SJohn.Forte@Sun.COM 	if ((cmd & 0xff000000) != STMF_IOCTL) {
4597836SJohn.Forte@Sun.COM 		return (ENOTTY);
4607836SJohn.Forte@Sun.COM 	}
4617836SJohn.Forte@Sun.COM 
4627836SJohn.Forte@Sun.COM 	if (drv_priv(credp) != 0) {
4637836SJohn.Forte@Sun.COM 		return (EPERM);
4647836SJohn.Forte@Sun.COM 	}
4657836SJohn.Forte@Sun.COM 
4667836SJohn.Forte@Sun.COM 	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
4677836SJohn.Forte@Sun.COM 	if (ret)
4687836SJohn.Forte@Sun.COM 		return (ret);
4697836SJohn.Forte@Sun.COM 	iocd->stmf_error = 0;
4707836SJohn.Forte@Sun.COM 
4717836SJohn.Forte@Sun.COM 	switch (cmd) {
4727836SJohn.Forte@Sun.COM 	case STMF_IOCTL_LU_LIST:
4739585STim.Szeto@Sun.COM 		/* retrieves both registered/unregistered */
4749585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
4759585STim.Szeto@Sun.COM 		id_list = &stmf_state.stmf_luid_list;
4769585STim.Szeto@Sun.COM 		n = min(id_list->id_count,
4779585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
4789585STim.Szeto@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
4799585STim.Szeto@Sun.COM 		luid_list = (slist_lu_t *)obuf;
4809585STim.Szeto@Sun.COM 		id_entry = id_list->idl_head;
4819585STim.Szeto@Sun.COM 		for (i = 0; i < n; i++) {
4829585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
4839585STim.Szeto@Sun.COM 			id_entry = id_entry->id_next;
4849585STim.Szeto@Sun.COM 		}
4859585STim.Szeto@Sun.COM 
4869585STim.Szeto@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (slist_lu_t);
4879585STim.Szeto@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
4889585STim.Szeto@Sun.COM 			id = (uint8_t *)ilu->ilu_lu->lu_id;
4899585STim.Szeto@Sun.COM 			if (stmf_lookup_id(id_list, 16, id + 4) == NULL) {
4909585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
4919585STim.Szeto@Sun.COM 				if (i < n) {
4929585STim.Szeto@Sun.COM 					bcopy(id + 4, luid_list[i].lu_guid,
4939585STim.Szeto@Sun.COM 					    sizeof (slist_lu_t));
4949585STim.Szeto@Sun.COM 					i++;
4959585STim.Szeto@Sun.COM 				}
4969585STim.Szeto@Sun.COM 			}
4979585STim.Szeto@Sun.COM 		}
4989585STim.Szeto@Sun.COM 		iocd->stmf_obuf_nentries = i;
4999585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5009585STim.Szeto@Sun.COM 		break;
5019585STim.Szeto@Sun.COM 
5029585STim.Szeto@Sun.COM 	case STMF_IOCTL_REG_LU_LIST:
5037836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5047836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus;
5057836SJohn.Forte@Sun.COM 		n = min(stmf_state.stmf_nlus,
5068662SJordan.Vaughan@Sun.com 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
5077836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
5087836SJohn.Forte@Sun.COM 		ilu = stmf_state.stmf_ilulist;
5097836SJohn.Forte@Sun.COM 		luid_list = (slist_lu_t *)obuf;
5107836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
5117836SJohn.Forte@Sun.COM 			uint8_t *id;
5127836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilu->ilu_lu->lu_id;
5137836SJohn.Forte@Sun.COM 			bcopy(id + 4, luid_list[i].lu_guid, 16);
5147836SJohn.Forte@Sun.COM 			ilu = ilu->ilu_next;
5157836SJohn.Forte@Sun.COM 		}
5167836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5177836SJohn.Forte@Sun.COM 		break;
5187836SJohn.Forte@Sun.COM 
5199585STim.Szeto@Sun.COM 	case STMF_IOCTL_VE_LU_LIST:
5209585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5219585STim.Szeto@Sun.COM 		id_list = &stmf_state.stmf_luid_list;
5229585STim.Szeto@Sun.COM 		n = min(id_list->id_count,
5239585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
5249585STim.Szeto@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
5259585STim.Szeto@Sun.COM 		iocd->stmf_obuf_nentries = n;
5269585STim.Szeto@Sun.COM 		luid_list = (slist_lu_t *)obuf;
5279585STim.Szeto@Sun.COM 		id_entry = id_list->idl_head;
5289585STim.Szeto@Sun.COM 		for (i = 0; i < n; i++) {
5299585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
5309585STim.Szeto@Sun.COM 			id_entry = id_entry->id_next;
5319585STim.Szeto@Sun.COM 		}
5329585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5339585STim.Szeto@Sun.COM 		break;
5349585STim.Szeto@Sun.COM 
5357836SJohn.Forte@Sun.COM 	case STMF_IOCTL_TARGET_PORT_LIST:
5367836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5377836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports;
5387836SJohn.Forte@Sun.COM 		n = min(stmf_state.stmf_nlports,
5398662SJordan.Vaughan@Sun.com 		    (iocd->stmf_obuf_size)/sizeof (slist_target_port_t));
5407836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
5417836SJohn.Forte@Sun.COM 		ilport = stmf_state.stmf_ilportlist;
5427836SJohn.Forte@Sun.COM 		lportid_list = (slist_target_port_t *)obuf;
5437836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
5447836SJohn.Forte@Sun.COM 			uint8_t *id;
5457836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
5467836SJohn.Forte@Sun.COM 			bcopy(id, lportid_list[i].target, id[3] + 4);
5477836SJohn.Forte@Sun.COM 			ilport = ilport->ilport_next;
5487836SJohn.Forte@Sun.COM 		}
5497836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5507836SJohn.Forte@Sun.COM 		break;
5517836SJohn.Forte@Sun.COM 
5527836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SESSION_LIST:
5537836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
5547836SJohn.Forte@Sun.COM 		if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) ||
5557836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < (p_id[3] + 4))) {
5567836SJohn.Forte@Sun.COM 			ret = EINVAL;
5577836SJohn.Forte@Sun.COM 			break;
5587836SJohn.Forte@Sun.COM 		}
5597836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
5607836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport; ilport =
5618662SJordan.Vaughan@Sun.com 		    ilport->ilport_next) {
5627836SJohn.Forte@Sun.COM 			uint8_t *id;
5637836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
5647836SJohn.Forte@Sun.COM 			if ((p_id[3] == id[3]) &&
5657836SJohn.Forte@Sun.COM 			    (bcmp(p_id + 4, id + 4, id[3]) == 0)) {
5667836SJohn.Forte@Sun.COM 				break;
5677836SJohn.Forte@Sun.COM 			}
5687836SJohn.Forte@Sun.COM 		}
5697836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
5707836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
5717836SJohn.Forte@Sun.COM 			ret = ENOENT;
5727836SJohn.Forte@Sun.COM 			break;
5737836SJohn.Forte@Sun.COM 		}
5747836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions;
5757836SJohn.Forte@Sun.COM 		n = min(ilport->ilport_nsessions,
5767836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t));
5777836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
5787836SJohn.Forte@Sun.COM 		iss = ilport->ilport_ss_list;
5797836SJohn.Forte@Sun.COM 		iss_list = (slist_scsi_session_t *)obuf;
5807836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
5817836SJohn.Forte@Sun.COM 			uint8_t *id;
5827836SJohn.Forte@Sun.COM 			id = (uint8_t *)iss->iss_ss->ss_rport_id;
5837836SJohn.Forte@Sun.COM 			bcopy(id, iss_list[i].initiator, id[3] + 4);
5847836SJohn.Forte@Sun.COM 			iss_list[i].creation_time = (uint32_t)
5857836SJohn.Forte@Sun.COM 			    iss->iss_creation_time;
5867836SJohn.Forte@Sun.COM 			if (iss->iss_ss->ss_rport_alias) {
5877836SJohn.Forte@Sun.COM 				(void) strncpy(iss_list[i].alias,
5887836SJohn.Forte@Sun.COM 				    iss->iss_ss->ss_rport_alias, 255);
5897836SJohn.Forte@Sun.COM 				iss_list[i].alias[255] = 0;
5907836SJohn.Forte@Sun.COM 			} else {
5917836SJohn.Forte@Sun.COM 				iss_list[i].alias[0] = 0;
5927836SJohn.Forte@Sun.COM 			}
5937836SJohn.Forte@Sun.COM 			iss = iss->iss_next;
5947836SJohn.Forte@Sun.COM 		}
5957836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
5967836SJohn.Forte@Sun.COM 		break;
5977836SJohn.Forte@Sun.COM 
5987836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_LU_PROPERTIES:
5997836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
6007836SJohn.Forte@Sun.COM 		if ((iocd->stmf_ibuf_size < 16) ||
6017836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) ||
6027836SJohn.Forte@Sun.COM 		    (p_id[0] == 0)) {
6037836SJohn.Forte@Sun.COM 			ret = EINVAL;
6047836SJohn.Forte@Sun.COM 			break;
6057836SJohn.Forte@Sun.COM 		}
6067836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
6077836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
6087836SJohn.Forte@Sun.COM 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
6097836SJohn.Forte@Sun.COM 				break;
6107836SJohn.Forte@Sun.COM 		}
6117836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
6127836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
6137836SJohn.Forte@Sun.COM 			ret = ENOENT;
6147836SJohn.Forte@Sun.COM 			break;
6157836SJohn.Forte@Sun.COM 		}
6167836SJohn.Forte@Sun.COM 		lup = (sioc_lu_props_t *)obuf;
6177836SJohn.Forte@Sun.COM 		bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16);
6187836SJohn.Forte@Sun.COM 		lup->lu_state = ilu->ilu_state & 0x0f;
6197836SJohn.Forte@Sun.COM 		lup->lu_present = 1; /* XXX */
6207836SJohn.Forte@Sun.COM 		(void) strncpy(lup->lu_provider_name,
6217836SJohn.Forte@Sun.COM 		    ilu->ilu_lu->lu_lp->lp_name, 255);
6227836SJohn.Forte@Sun.COM 		lup->lu_provider_name[254] = 0;
6237836SJohn.Forte@Sun.COM 		if (ilu->ilu_lu->lu_alias) {
6247836SJohn.Forte@Sun.COM 			(void) strncpy(lup->lu_alias,
6257836SJohn.Forte@Sun.COM 			    ilu->ilu_lu->lu_alias, 255);
6267836SJohn.Forte@Sun.COM 			lup->lu_alias[255] = 0;
6277836SJohn.Forte@Sun.COM 		} else {
6287836SJohn.Forte@Sun.COM 			lup->lu_alias[0] = 0;
6297836SJohn.Forte@Sun.COM 		}
6307836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
6317836SJohn.Forte@Sun.COM 		break;
6327836SJohn.Forte@Sun.COM 
6337836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES:
6347836SJohn.Forte@Sun.COM 		p_id = (uint8_t *)ibuf;
6357836SJohn.Forte@Sun.COM 		if ((p_id == NULL) ||
6367836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < (p_id[3] + 4)) ||
6377836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size <
6387836SJohn.Forte@Sun.COM 		    sizeof (sioc_target_port_props_t))) {
6397836SJohn.Forte@Sun.COM 			ret = EINVAL;
6407836SJohn.Forte@Sun.COM 			break;
6417836SJohn.Forte@Sun.COM 		}
6427836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
6437836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport;
6447836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
6457836SJohn.Forte@Sun.COM 			uint8_t *id;
6467836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
6477836SJohn.Forte@Sun.COM 			if ((p_id[3] == id[3]) &&
6487836SJohn.Forte@Sun.COM 			    (bcmp(p_id+4, id+4, id[3]) == 0))
6497836SJohn.Forte@Sun.COM 				break;
6507836SJohn.Forte@Sun.COM 		}
6517836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
6527836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
6537836SJohn.Forte@Sun.COM 			ret = ENOENT;
6547836SJohn.Forte@Sun.COM 			break;
6557836SJohn.Forte@Sun.COM 		}
6567836SJohn.Forte@Sun.COM 		lportp = (sioc_target_port_props_t *)obuf;
6577836SJohn.Forte@Sun.COM 		bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id,
6587836SJohn.Forte@Sun.COM 		    ilport->ilport_lport->lport_id->ident_length + 4);
6597836SJohn.Forte@Sun.COM 		lportp->tgt_state = ilport->ilport_state & 0x0f;
6607836SJohn.Forte@Sun.COM 		lportp->tgt_present = 1; /* XXX */
6617836SJohn.Forte@Sun.COM 		(void) strncpy(lportp->tgt_provider_name,
6627836SJohn.Forte@Sun.COM 		    ilport->ilport_lport->lport_pp->pp_name, 255);
6637836SJohn.Forte@Sun.COM 		lportp->tgt_provider_name[254] = 0;
6647836SJohn.Forte@Sun.COM 		if (ilport->ilport_lport->lport_alias) {
6657836SJohn.Forte@Sun.COM 			(void) strncpy(lportp->tgt_alias,
6667836SJohn.Forte@Sun.COM 			    ilport->ilport_lport->lport_alias, 255);
6677836SJohn.Forte@Sun.COM 			lportp->tgt_alias[255] = 0;
6687836SJohn.Forte@Sun.COM 		} else {
6697836SJohn.Forte@Sun.COM 			lportp->tgt_alias[0] = 0;
6707836SJohn.Forte@Sun.COM 		}
6717836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
6727836SJohn.Forte@Sun.COM 		break;
6737836SJohn.Forte@Sun.COM 
6747836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_STMF_STATE:
6757836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
6767836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
6777836SJohn.Forte@Sun.COM 			ret = EINVAL;
6787836SJohn.Forte@Sun.COM 			break;
6797836SJohn.Forte@Sun.COM 		}
6807836SJohn.Forte@Sun.COM 		ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf);
6817836SJohn.Forte@Sun.COM 		break;
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_STMF_STATE:
6847836SJohn.Forte@Sun.COM 		if ((obuf == NULL) ||
6857836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) {
6867836SJohn.Forte@Sun.COM 			ret = EINVAL;
6877836SJohn.Forte@Sun.COM 			break;
6887836SJohn.Forte@Sun.COM 		}
6897836SJohn.Forte@Sun.COM 		ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf);
6907836SJohn.Forte@Sun.COM 		break;
6917836SJohn.Forte@Sun.COM 
6927836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_LU_STATE:
6937836SJohn.Forte@Sun.COM 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
6947836SJohn.Forte@Sun.COM 		ssi.st_additional_info = NULL;
6957836SJohn.Forte@Sun.COM 		std = (stmf_state_desc_t *)ibuf;
6967836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
6977836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
6987836SJohn.Forte@Sun.COM 			ret = EINVAL;
6997836SJohn.Forte@Sun.COM 			break;
7007836SJohn.Forte@Sun.COM 		}
7017836SJohn.Forte@Sun.COM 		p_id = std->ident;
7027836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7037836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_inventory_locked) {
7047836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7057836SJohn.Forte@Sun.COM 			ret = EBUSY;
7067836SJohn.Forte@Sun.COM 			break;
7077836SJohn.Forte@Sun.COM 		}
7087836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
7097836SJohn.Forte@Sun.COM 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
7107836SJohn.Forte@Sun.COM 				break;
7117836SJohn.Forte@Sun.COM 		}
7127836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
7137836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7147836SJohn.Forte@Sun.COM 			ret = ENOENT;
7157836SJohn.Forte@Sun.COM 			break;
7167836SJohn.Forte@Sun.COM 		}
7177836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
7187836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7197836SJohn.Forte@Sun.COM 		cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE :
7207836SJohn.Forte@Sun.COM 		    STMF_CMD_LU_OFFLINE;
7217836SJohn.Forte@Sun.COM 		ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi);
7227836SJohn.Forte@Sun.COM 		if (ctl_ret == STMF_ALREADY)
7237836SJohn.Forte@Sun.COM 			ret = 0;
7247836SJohn.Forte@Sun.COM 		else if (ctl_ret != STMF_SUCCESS)
7257836SJohn.Forte@Sun.COM 			ret = EIO;
7267836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7277836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
7287836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7297836SJohn.Forte@Sun.COM 		break;
7307836SJohn.Forte@Sun.COM 
7317836SJohn.Forte@Sun.COM 	case STMF_IOCTL_SET_TARGET_PORT_STATE:
7327836SJohn.Forte@Sun.COM 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
7337836SJohn.Forte@Sun.COM 		ssi.st_additional_info = NULL;
7347836SJohn.Forte@Sun.COM 		std = (stmf_state_desc_t *)ibuf;
7357836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
7367836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
7377836SJohn.Forte@Sun.COM 			ret = EINVAL;
7387836SJohn.Forte@Sun.COM 			break;
7397836SJohn.Forte@Sun.COM 		}
7407836SJohn.Forte@Sun.COM 		p_id = std->ident;
7417836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7427836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_inventory_locked) {
7437836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7447836SJohn.Forte@Sun.COM 			ret = EBUSY;
7457836SJohn.Forte@Sun.COM 			break;
7467836SJohn.Forte@Sun.COM 		}
7477836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport;
7487836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
7497836SJohn.Forte@Sun.COM 			uint8_t *id;
7507836SJohn.Forte@Sun.COM 			id = (uint8_t *)ilport->ilport_lport->lport_id;
7517836SJohn.Forte@Sun.COM 			if ((id[3] == p_id[3]) &&
7527836SJohn.Forte@Sun.COM 			    (bcmp(id+4, p_id+4, id[3]) == 0)) {
7537836SJohn.Forte@Sun.COM 				break;
7547836SJohn.Forte@Sun.COM 			}
7557836SJohn.Forte@Sun.COM 		}
7567836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
7577836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
7587836SJohn.Forte@Sun.COM 			ret = ENOENT;
7597836SJohn.Forte@Sun.COM 			break;
7607836SJohn.Forte@Sun.COM 		}
7617836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
7627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7637836SJohn.Forte@Sun.COM 		cmd = (std->state == STMF_STATE_ONLINE) ?
7647836SJohn.Forte@Sun.COM 		    STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE;
7657836SJohn.Forte@Sun.COM 		ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi);
7667836SJohn.Forte@Sun.COM 		if (ctl_ret == STMF_ALREADY)
7677836SJohn.Forte@Sun.COM 			ret = 0;
7687836SJohn.Forte@Sun.COM 		else if (ctl_ret != STMF_SUCCESS)
7697836SJohn.Forte@Sun.COM 			ret = EIO;
7707836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7717836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
7727836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
7737836SJohn.Forte@Sun.COM 		break;
7747836SJohn.Forte@Sun.COM 
7757836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_HG_ENTRY:
7767836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST;
7777836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
7787836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_TG_ENTRY:
7797836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
7807836SJohn.Forte@Sun.COM 			ret = EACCES;
7817836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
7827836SJohn.Forte@Sun.COM 			break;
7837836SJohn.Forte@Sun.COM 		}
7847836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_ADD_TG_ENTRY) {
7857836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET;
7867836SJohn.Forte@Sun.COM 		}
7877836SJohn.Forte@Sun.COM 		grp_entry = (stmf_group_op_data_t *)ibuf;
7887836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
7897836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
7907836SJohn.Forte@Sun.COM 			ret = EINVAL;
7917836SJohn.Forte@Sun.COM 			break;
7927836SJohn.Forte@Sun.COM 		}
7937836SJohn.Forte@Sun.COM 		if (grp_entry->group.name[0] == '*') {
7947836SJohn.Forte@Sun.COM 			ret = EINVAL;
7957836SJohn.Forte@Sun.COM 			break; /* not allowed */
7967836SJohn.Forte@Sun.COM 		}
7977836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
7987836SJohn.Forte@Sun.COM 		ret = stmf_add_group_member(grp_entry->group.name,
7997836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
8007836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
8017836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
8027836SJohn.Forte@Sun.COM 		    idtype,
8037836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
8047836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8057836SJohn.Forte@Sun.COM 		break;
8067836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HG_ENTRY:
8077836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST;
8087836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8097836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TG_ENTRY:
8107836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8117836SJohn.Forte@Sun.COM 			ret = EACCES;
8127836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8137836SJohn.Forte@Sun.COM 			break;
8147836SJohn.Forte@Sun.COM 		}
8157836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) {
8167836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET;
8177836SJohn.Forte@Sun.COM 		}
8187836SJohn.Forte@Sun.COM 		grp_entry = (stmf_group_op_data_t *)ibuf;
8197836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8207836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
8217836SJohn.Forte@Sun.COM 			ret = EINVAL;
8227836SJohn.Forte@Sun.COM 			break;
8237836SJohn.Forte@Sun.COM 		}
8247836SJohn.Forte@Sun.COM 		if (grp_entry->group.name[0] == '*') {
8257836SJohn.Forte@Sun.COM 			ret = EINVAL;
8267836SJohn.Forte@Sun.COM 			break; /* not allowed */
8277836SJohn.Forte@Sun.COM 		}
8287836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8297836SJohn.Forte@Sun.COM 		ret = stmf_remove_group_member(grp_entry->group.name,
8307836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
8317836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
8327836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
8337836SJohn.Forte@Sun.COM 		    idtype,
8347836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
8357836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8367836SJohn.Forte@Sun.COM 		break;
8377836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_HOST_GROUP:
8387836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
8397836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8407836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_TARGET_GROUP:
8417836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8427836SJohn.Forte@Sun.COM 			ret = EACCES;
8437836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8447836SJohn.Forte@Sun.COM 			break;
8457836SJohn.Forte@Sun.COM 		}
8467836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8477836SJohn.Forte@Sun.COM 
8487836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP)
8497836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8507836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8517836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8527836SJohn.Forte@Sun.COM 			ret = EINVAL;
8537836SJohn.Forte@Sun.COM 			break;
8547836SJohn.Forte@Sun.COM 		}
8557836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8567836SJohn.Forte@Sun.COM 			ret = EINVAL;
8577836SJohn.Forte@Sun.COM 			break; /* not allowed */
8587836SJohn.Forte@Sun.COM 		}
8597836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8607836SJohn.Forte@Sun.COM 		ret = stmf_add_group(grpname->name,
8617836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
8627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8637836SJohn.Forte@Sun.COM 		break;
8647836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HOST_GROUP:
8657836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
8667836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8677836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TARGET_GROUP:
8687836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8697836SJohn.Forte@Sun.COM 			ret = EACCES;
8707836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8717836SJohn.Forte@Sun.COM 			break;
8727836SJohn.Forte@Sun.COM 		}
8737836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8747836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP)
8757836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8767836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8777836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8787836SJohn.Forte@Sun.COM 			ret = EINVAL;
8797836SJohn.Forte@Sun.COM 			break;
8807836SJohn.Forte@Sun.COM 		}
8817836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8827836SJohn.Forte@Sun.COM 			ret = EINVAL;
8837836SJohn.Forte@Sun.COM 			break; /* not allowed */
8847836SJohn.Forte@Sun.COM 		}
8857836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8867836SJohn.Forte@Sun.COM 		ret = stmf_remove_group(grpname->name,
8877836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
8887836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8897836SJohn.Forte@Sun.COM 		break;
8907836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_VIEW_ENTRY:
8917836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8927836SJohn.Forte@Sun.COM 			ret = EACCES;
8937836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8947836SJohn.Forte@Sun.COM 			break;
8957836SJohn.Forte@Sun.COM 		}
8967836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
8977836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8987836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
8997836SJohn.Forte@Sun.COM 			ret = EINVAL;
9007836SJohn.Forte@Sun.COM 			break;
9017836SJohn.Forte@Sun.COM 		}
9027836SJohn.Forte@Sun.COM 		if (!ve->ve_lu_number_valid)
9037836SJohn.Forte@Sun.COM 			ve->ve_lu_nbr[2] = 0xFF;
9047836SJohn.Forte@Sun.COM 		if (ve->ve_all_hosts) {
9057836SJohn.Forte@Sun.COM 			ve->ve_host_group.name[0] = '*';
9067836SJohn.Forte@Sun.COM 			ve->ve_host_group.name_size = 1;
9077836SJohn.Forte@Sun.COM 		}
9087836SJohn.Forte@Sun.COM 		if (ve->ve_all_targets) {
9097836SJohn.Forte@Sun.COM 			ve->ve_target_group.name[0] = '*';
9107836SJohn.Forte@Sun.COM 			ve->ve_target_group.name_size = 1;
9117836SJohn.Forte@Sun.COM 		}
9127836SJohn.Forte@Sun.COM 		if (ve->ve_ndx_valid)
9137836SJohn.Forte@Sun.COM 			veid = ve->ve_ndx;
9147836SJohn.Forte@Sun.COM 		else
9157836SJohn.Forte@Sun.COM 			veid = 0xffffffff;
9167836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9177836SJohn.Forte@Sun.COM 		ret = stmf_add_ve(ve->ve_host_group.name,
9187836SJohn.Forte@Sun.COM 		    ve->ve_host_group.name_size,
9197836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name,
9207836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name_size,
9217836SJohn.Forte@Sun.COM 		    ve->ve_guid,
9227836SJohn.Forte@Sun.COM 		    &veid,
9237836SJohn.Forte@Sun.COM 		    ve->ve_lu_nbr,
9247836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
9257836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9267836SJohn.Forte@Sun.COM 		if (ret == 0 &&
9277836SJohn.Forte@Sun.COM 		    (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) &&
9287836SJohn.Forte@Sun.COM 		    iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) {
9297836SJohn.Forte@Sun.COM 			stmf_view_op_entry_t *ve_ret =
9307836SJohn.Forte@Sun.COM 			    (stmf_view_op_entry_t *)obuf;
9317836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = 1;
9327836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = 1;
9337836SJohn.Forte@Sun.COM 			if (!ve->ve_ndx_valid) {
9347836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx = veid;
9357836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx_valid = 1;
9367836SJohn.Forte@Sun.COM 			}
9377836SJohn.Forte@Sun.COM 			if (!ve->ve_lu_number_valid) {
9387836SJohn.Forte@Sun.COM 				ve_ret->ve_lu_number_valid = 1;
9397836SJohn.Forte@Sun.COM 				bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8);
9407836SJohn.Forte@Sun.COM 			}
9417836SJohn.Forte@Sun.COM 		}
9427836SJohn.Forte@Sun.COM 		break;
9437836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_VIEW_ENTRY:
9447836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
9457836SJohn.Forte@Sun.COM 			ret = EACCES;
9467836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
9477836SJohn.Forte@Sun.COM 			break;
9487836SJohn.Forte@Sun.COM 		}
9497836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
9507836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9517836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
9527836SJohn.Forte@Sun.COM 			ret = EINVAL;
9537836SJohn.Forte@Sun.COM 			break;
9547836SJohn.Forte@Sun.COM 		}
9557836SJohn.Forte@Sun.COM 		if (!ve->ve_ndx_valid) {
9567836SJohn.Forte@Sun.COM 			ret = EINVAL;
9577836SJohn.Forte@Sun.COM 			break;
9587836SJohn.Forte@Sun.COM 		}
9597836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9607836SJohn.Forte@Sun.COM 		ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx,
9617836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
9627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9637836SJohn.Forte@Sun.COM 		break;
9647836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_LIST:
9657836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
9667836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
9677836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_LIST:
9687836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_LIST)
9697836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
9707836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9717836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
9727836SJohn.Forte@Sun.COM 		n = min(id_list->id_count,
9737836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t));
9747836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
9757836SJohn.Forte@Sun.COM 		id_entry = id_list->idl_head;
9767836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)obuf;
9777836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
9789585STim.Szeto@Sun.COM 			if (id_entry->id_data[0] == '*') {
9799585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries > 0) {
9809585STim.Szeto@Sun.COM 					iocd->stmf_obuf_nentries--;
9819585STim.Szeto@Sun.COM 				}
9829585STim.Szeto@Sun.COM 				id_entry = id_entry->id_next;
9839585STim.Szeto@Sun.COM 				continue;
9849585STim.Szeto@Sun.COM 			}
9859585STim.Szeto@Sun.COM 			grpname->name_size = id_entry->id_data_size;
9869585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, grpname->name,
9877836SJohn.Forte@Sun.COM 			    id_entry->id_data_size);
9889585STim.Szeto@Sun.COM 			grpname++;
9897836SJohn.Forte@Sun.COM 			id_entry = id_entry->id_next;
9907836SJohn.Forte@Sun.COM 		}
9917836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9927836SJohn.Forte@Sun.COM 		break;
9937836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_ENTRIES:
9947836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
9957836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
9967836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_ENTRIES:
9977836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
9987836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9997836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
10007836SJohn.Forte@Sun.COM 			ret = EINVAL;
10017836SJohn.Forte@Sun.COM 			break;
10027836SJohn.Forte@Sun.COM 		}
10037836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_ENTRIES) {
10047836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
10057836SJohn.Forte@Sun.COM 		}
10067836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
10077836SJohn.Forte@Sun.COM 		id_entry = stmf_lookup_id(id_list, grpname->name_size,
10087836SJohn.Forte@Sun.COM 		    grpname->name);
10097836SJohn.Forte@Sun.COM 		if (!id_entry)
10107836SJohn.Forte@Sun.COM 			ret = ENODEV;
10117836SJohn.Forte@Sun.COM 		else {
10127836SJohn.Forte@Sun.COM 			stmf_ge_ident_t *grp_entry;
10137836SJohn.Forte@Sun.COM 			id_list = (stmf_id_list_t *)id_entry->id_impl_specific;
10147836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = id_list->id_count;
10157836SJohn.Forte@Sun.COM 			n = min(id_list->id_count,
10167836SJohn.Forte@Sun.COM 			    iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t));
10177836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = n;
10187836SJohn.Forte@Sun.COM 			id_entry = id_list->idl_head;
10197836SJohn.Forte@Sun.COM 			grp_entry = (stmf_ge_ident_t *)obuf;
10207836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
10219585STim.Szeto@Sun.COM 				bcopy(id_entry->id_data, grp_entry->ident,
10227836SJohn.Forte@Sun.COM 				    id_entry->id_data_size);
10239585STim.Szeto@Sun.COM 				grp_entry->ident_size = id_entry->id_data_size;
10247836SJohn.Forte@Sun.COM 				id_entry = id_entry->id_next;
10259585STim.Szeto@Sun.COM 				grp_entry++;
10267836SJohn.Forte@Sun.COM 			}
10277836SJohn.Forte@Sun.COM 		}
10287836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10297836SJohn.Forte@Sun.COM 		break;
10309585STim.Szeto@Sun.COM 
10317836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_VE_LIST:
10327836SJohn.Forte@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
10337836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
10347836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)obuf;
10359585STim.Szeto@Sun.COM 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
10369585STim.Szeto@Sun.COM 		    id_entry; id_entry = id_entry->id_next) {
10379585STim.Szeto@Sun.COM 			for (view_entry = (stmf_view_entry_t *)
10389585STim.Szeto@Sun.COM 			    id_entry->id_impl_specific; view_entry;
10399585STim.Szeto@Sun.COM 			    view_entry = view_entry->ve_next) {
10409585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
10419585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries >= n)
10429585STim.Szeto@Sun.COM 					continue;
10437836SJohn.Forte@Sun.COM 				ve->ve_ndx_valid = 1;
10447836SJohn.Forte@Sun.COM 				ve->ve_ndx = view_entry->ve_id;
10457836SJohn.Forte@Sun.COM 				ve->ve_lu_number_valid = 1;
10467836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
10477836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
10487836SJohn.Forte@Sun.COM 				    view_entry->ve_luid->id_data_size);
10499585STim.Szeto@Sun.COM 				if (view_entry->ve_hg->id_data[0] == '*') {
10507836SJohn.Forte@Sun.COM 					ve->ve_all_hosts = 1;
10519585STim.Szeto@Sun.COM 				} else {
10527836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_hg->id_data,
10537836SJohn.Forte@Sun.COM 					    ve->ve_host_group.name,
10547836SJohn.Forte@Sun.COM 					    view_entry->ve_hg->id_data_size);
10559585STim.Szeto@Sun.COM 					ve->ve_host_group.name_size =
10569585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size;
10579585STim.Szeto@Sun.COM 				}
10589585STim.Szeto@Sun.COM 
10599585STim.Szeto@Sun.COM 				if (view_entry->ve_tg->id_data[0] == '*') {
10607836SJohn.Forte@Sun.COM 					ve->ve_all_targets = 1;
10619585STim.Szeto@Sun.COM 				} else {
10627836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_tg->id_data,
10637836SJohn.Forte@Sun.COM 					    ve->ve_target_group.name,
10647836SJohn.Forte@Sun.COM 					    view_entry->ve_tg->id_data_size);
10659585STim.Szeto@Sun.COM 					ve->ve_target_group.name_size =
10669585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size;
10679585STim.Szeto@Sun.COM 				}
10689585STim.Szeto@Sun.COM 				ve++;
10697836SJohn.Forte@Sun.COM 				iocd->stmf_obuf_nentries++;
10707836SJohn.Forte@Sun.COM 			}
10717836SJohn.Forte@Sun.COM 		}
10727836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10737836SJohn.Forte@Sun.COM 		break;
10749585STim.Szeto@Sun.COM 
10759585STim.Szeto@Sun.COM 	case STMF_IOCTL_LU_VE_LIST:
10769585STim.Szeto@Sun.COM 		p_id = (uint8_t *)ibuf;
10779585STim.Szeto@Sun.COM 		if ((iocd->stmf_ibuf_size != 16) ||
10789585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) {
10799585STim.Szeto@Sun.COM 			ret = EINVAL;
10809585STim.Szeto@Sun.COM 			break;
10819585STim.Szeto@Sun.COM 		}
10829585STim.Szeto@Sun.COM 
10839585STim.Szeto@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
10849585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
10859585STim.Szeto@Sun.COM 		ve = (stmf_view_op_entry_t *)obuf;
10869585STim.Szeto@Sun.COM 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
10879585STim.Szeto@Sun.COM 		    id_entry; id_entry = id_entry->id_next) {
10889585STim.Szeto@Sun.COM 			if (bcmp(id_entry->id_data, p_id, 16) != 0)
10899585STim.Szeto@Sun.COM 				continue;
10909585STim.Szeto@Sun.COM 			for (view_entry = (stmf_view_entry_t *)
10919585STim.Szeto@Sun.COM 			    id_entry->id_impl_specific; view_entry;
10929585STim.Szeto@Sun.COM 			    view_entry = view_entry->ve_next) {
10939585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
10949585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries >= n)
10959585STim.Szeto@Sun.COM 					continue;
10969585STim.Szeto@Sun.COM 				ve->ve_ndx_valid = 1;
10979585STim.Szeto@Sun.COM 				ve->ve_ndx = view_entry->ve_id;
10989585STim.Szeto@Sun.COM 				ve->ve_lu_number_valid = 1;
10999585STim.Szeto@Sun.COM 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
11009585STim.Szeto@Sun.COM 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
11019585STim.Szeto@Sun.COM 				    view_entry->ve_luid->id_data_size);
11029585STim.Szeto@Sun.COM 				if (view_entry->ve_hg->id_data[0] == '*') {
11039585STim.Szeto@Sun.COM 					ve->ve_all_hosts = 1;
11049585STim.Szeto@Sun.COM 				} else {
11059585STim.Szeto@Sun.COM 					bcopy(view_entry->ve_hg->id_data,
11069585STim.Szeto@Sun.COM 					    ve->ve_host_group.name,
11079585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size);
11089585STim.Szeto@Sun.COM 					ve->ve_host_group.name_size =
11099585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size;
11109585STim.Szeto@Sun.COM 				}
11119585STim.Szeto@Sun.COM 
11129585STim.Szeto@Sun.COM 				if (view_entry->ve_tg->id_data[0] == '*') {
11139585STim.Szeto@Sun.COM 					ve->ve_all_targets = 1;
11149585STim.Szeto@Sun.COM 				} else {
11159585STim.Szeto@Sun.COM 					bcopy(view_entry->ve_tg->id_data,
11169585STim.Szeto@Sun.COM 					    ve->ve_target_group.name,
11179585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size);
11189585STim.Szeto@Sun.COM 					ve->ve_target_group.name_size =
11199585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size;
11209585STim.Szeto@Sun.COM 				}
11219585STim.Szeto@Sun.COM 				ve++;
11229585STim.Szeto@Sun.COM 				iocd->stmf_obuf_nentries++;
11239585STim.Szeto@Sun.COM 			}
11249585STim.Szeto@Sun.COM 			break;
11259585STim.Szeto@Sun.COM 		}
11269585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
11279585STim.Szeto@Sun.COM 		break;
11289585STim.Szeto@Sun.COM 
11297836SJohn.Forte@Sun.COM 	case STMF_IOCTL_LOAD_PP_DATA:
11307836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
11317836SJohn.Forte@Sun.COM 			ret = EACCES;
11327836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
11337836SJohn.Forte@Sun.COM 			break;
11347836SJohn.Forte@Sun.COM 		}
11357836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
11367836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
11377836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
11387836SJohn.Forte@Sun.COM 			ret = EINVAL;
11397836SJohn.Forte@Sun.COM 			break;
11407836SJohn.Forte@Sun.COM 		}
11419585STim.Szeto@Sun.COM 		/* returned token */
11429585STim.Szeto@Sun.COM 		ppi_token = (uint64_t *)obuf;
11439585STim.Szeto@Sun.COM 		if ((ppi_token == NULL) ||
11449585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (uint64_t))) {
11459585STim.Szeto@Sun.COM 			ret = EINVAL;
11469585STim.Szeto@Sun.COM 			break;
11479585STim.Szeto@Sun.COM 		}
11489585STim.Szeto@Sun.COM 		ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error);
11499585STim.Szeto@Sun.COM 		break;
11509585STim.Szeto@Sun.COM 
11519585STim.Szeto@Sun.COM 	case STMF_IOCTL_GET_PP_DATA:
11529585STim.Szeto@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
11539585STim.Szeto@Sun.COM 			ret = EACCES;
11549585STim.Szeto@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
11559585STim.Szeto@Sun.COM 			break;
11569585STim.Szeto@Sun.COM 		}
11579585STim.Szeto@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
11589585STim.Szeto@Sun.COM 		if (ppi == NULL ||
11599585STim.Szeto@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
11609585STim.Szeto@Sun.COM 			ret = EINVAL;
11619585STim.Szeto@Sun.COM 			break;
11629585STim.Szeto@Sun.COM 		}
11639585STim.Szeto@Sun.COM 		ppi_out = (stmf_ppioctl_data_t *)obuf;
11649585STim.Szeto@Sun.COM 		if ((ppi_out == NULL) ||
11659585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) {
11669585STim.Szeto@Sun.COM 			ret = EINVAL;
11679585STim.Szeto@Sun.COM 			break;
11689585STim.Szeto@Sun.COM 		}
11699585STim.Szeto@Sun.COM 		ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error);
11707836SJohn.Forte@Sun.COM 		break;
11717836SJohn.Forte@Sun.COM 
11727836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_PP_DATA:
11737836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
11747836SJohn.Forte@Sun.COM 			ret = EACCES;
11757836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
11767836SJohn.Forte@Sun.COM 			break;
11777836SJohn.Forte@Sun.COM 		}
11787836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
11797836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
11807836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
11817836SJohn.Forte@Sun.COM 			ret = EINVAL;
11827836SJohn.Forte@Sun.COM 			break;
11837836SJohn.Forte@Sun.COM 		}
11847836SJohn.Forte@Sun.COM 		ret = stmf_delete_ppd_ioctl(ppi);
11857836SJohn.Forte@Sun.COM 		break;
11867836SJohn.Forte@Sun.COM 
11877836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_TRACE:
11887836SJohn.Forte@Sun.COM 		stmf_trace_clear();
11897836SJohn.Forte@Sun.COM 		break;
11907836SJohn.Forte@Sun.COM 
11917836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_TRACE:
11927836SJohn.Forte@Sun.COM 		if (iocd->stmf_ibuf_size && ibuf) {
11937836SJohn.Forte@Sun.COM 			((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0;
11947836SJohn.Forte@Sun.COM 			stmf_trace("\nstradm", "%s\n", ibuf);
11957836SJohn.Forte@Sun.COM 		}
11967836SJohn.Forte@Sun.COM 		break;
11977836SJohn.Forte@Sun.COM 
11987836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE_POSITION:
11997836SJohn.Forte@Sun.COM 		if (obuf && (iocd->stmf_obuf_size > 3)) {
12007836SJohn.Forte@Sun.COM 			mutex_enter(&trace_buf_lock);
12017836SJohn.Forte@Sun.COM 			*((int *)obuf) = trace_buf_curndx;
12027836SJohn.Forte@Sun.COM 			mutex_exit(&trace_buf_lock);
12037836SJohn.Forte@Sun.COM 		} else {
12047836SJohn.Forte@Sun.COM 			ret = EINVAL;
12057836SJohn.Forte@Sun.COM 		}
12067836SJohn.Forte@Sun.COM 		break;
12077836SJohn.Forte@Sun.COM 
12087836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE:
12097836SJohn.Forte@Sun.COM 		if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) {
12107836SJohn.Forte@Sun.COM 			ret = EINVAL;
12117836SJohn.Forte@Sun.COM 			break;
12127836SJohn.Forte@Sun.COM 		}
12137836SJohn.Forte@Sun.COM 		i = *((int *)ibuf);
12147836SJohn.Forte@Sun.COM 		if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) >
12157836SJohn.Forte@Sun.COM 		    trace_buf_size)) {
12167836SJohn.Forte@Sun.COM 			ret = EINVAL;
12177836SJohn.Forte@Sun.COM 			break;
12187836SJohn.Forte@Sun.COM 		}
12197836SJohn.Forte@Sun.COM 		mutex_enter(&trace_buf_lock);
12207836SJohn.Forte@Sun.COM 		bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size);
12217836SJohn.Forte@Sun.COM 		mutex_exit(&trace_buf_lock);
12227836SJohn.Forte@Sun.COM 		break;
12237836SJohn.Forte@Sun.COM 
12247836SJohn.Forte@Sun.COM 	default:
12257836SJohn.Forte@Sun.COM 		ret = ENOTTY;
12267836SJohn.Forte@Sun.COM 	}
12277836SJohn.Forte@Sun.COM 
12287836SJohn.Forte@Sun.COM 	if (ret == 0) {
12297836SJohn.Forte@Sun.COM 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
12307836SJohn.Forte@Sun.COM 	} else if (iocd->stmf_error) {
12317836SJohn.Forte@Sun.COM 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
12327836SJohn.Forte@Sun.COM 	}
12337836SJohn.Forte@Sun.COM 	if (obuf) {
12347836SJohn.Forte@Sun.COM 		kmem_free(obuf, iocd->stmf_obuf_size);
12357836SJohn.Forte@Sun.COM 		obuf = NULL;
12367836SJohn.Forte@Sun.COM 	}
12377836SJohn.Forte@Sun.COM 	if (ibuf) {
12387836SJohn.Forte@Sun.COM 		kmem_free(ibuf, iocd->stmf_ibuf_size);
12397836SJohn.Forte@Sun.COM 		ibuf = NULL;
12407836SJohn.Forte@Sun.COM 	}
12417836SJohn.Forte@Sun.COM 	kmem_free(iocd, sizeof (stmf_iocdata_t));
12427836SJohn.Forte@Sun.COM 	return (ret);
12437836SJohn.Forte@Sun.COM }
12447836SJohn.Forte@Sun.COM 
12457836SJohn.Forte@Sun.COM static int
12467836SJohn.Forte@Sun.COM stmf_get_service_state()
12477836SJohn.Forte@Sun.COM {
12487836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
12497836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
12507836SJohn.Forte@Sun.COM 	int online = 0;
12517836SJohn.Forte@Sun.COM 	int offline = 0;
12527836SJohn.Forte@Sun.COM 	int onlining = 0;
12537836SJohn.Forte@Sun.COM 	int offlining = 0;
12547836SJohn.Forte@Sun.COM 
12557836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
12567836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
12577836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
12587836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE)
12597836SJohn.Forte@Sun.COM 			offline++;
12607836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINE)
12617836SJohn.Forte@Sun.COM 			online++;
12627836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINING)
12637836SJohn.Forte@Sun.COM 			onlining++;
12647836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_OFFLINING)
12657836SJohn.Forte@Sun.COM 			offlining++;
12667836SJohn.Forte@Sun.COM 	}
12677836SJohn.Forte@Sun.COM 
12687836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
12697836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
12707836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE)
12717836SJohn.Forte@Sun.COM 			offline++;
12727836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINE)
12737836SJohn.Forte@Sun.COM 			online++;
12747836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINING)
12757836SJohn.Forte@Sun.COM 			onlining++;
12767836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_OFFLINING)
12777836SJohn.Forte@Sun.COM 			offlining++;
12787836SJohn.Forte@Sun.COM 	}
12797836SJohn.Forte@Sun.COM 
12807836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
12817836SJohn.Forte@Sun.COM 		if (onlining)
12827836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINING);
12837836SJohn.Forte@Sun.COM 		else
12847836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINE);
12857836SJohn.Forte@Sun.COM 	}
12867836SJohn.Forte@Sun.COM 
12877836SJohn.Forte@Sun.COM 	if (offlining) {
12887836SJohn.Forte@Sun.COM 		return (STMF_STATE_OFFLINING);
12897836SJohn.Forte@Sun.COM 	}
12907836SJohn.Forte@Sun.COM 
12917836SJohn.Forte@Sun.COM 	return (STMF_STATE_OFFLINE);
12927836SJohn.Forte@Sun.COM }
12937836SJohn.Forte@Sun.COM 
12947836SJohn.Forte@Sun.COM static int
12957836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std)
12967836SJohn.Forte@Sun.COM {
12977836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
12987836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
12997836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssi;
13007836SJohn.Forte@Sun.COM 	int svc_state;
13017836SJohn.Forte@Sun.COM 
13027836SJohn.Forte@Sun.COM 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
13037836SJohn.Forte@Sun.COM 	ssi.st_additional_info = NULL;
13047836SJohn.Forte@Sun.COM 
13057836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
13067836SJohn.Forte@Sun.COM 	if (!stmf_state.stmf_exclusive_open) {
13077836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13087836SJohn.Forte@Sun.COM 		return (EACCES);
13097836SJohn.Forte@Sun.COM 	}
13107836SJohn.Forte@Sun.COM 
13117836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
13127836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13137836SJohn.Forte@Sun.COM 		return (EBUSY);
13147836SJohn.Forte@Sun.COM 	}
13157836SJohn.Forte@Sun.COM 
13167836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_ONLINE) &&
13177836SJohn.Forte@Sun.COM 	    (std->state != STMF_STATE_OFFLINE)) {
13187836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13197836SJohn.Forte@Sun.COM 		return (EINVAL);
13207836SJohn.Forte@Sun.COM 	}
13217836SJohn.Forte@Sun.COM 
13227836SJohn.Forte@Sun.COM 	svc_state = stmf_get_service_state();
13237836SJohn.Forte@Sun.COM 	if ((svc_state == STMF_STATE_OFFLINING) ||
13247836SJohn.Forte@Sun.COM 	    (svc_state == STMF_STATE_ONLINING)) {
13257836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13267836SJohn.Forte@Sun.COM 		return (EBUSY);
13277836SJohn.Forte@Sun.COM 	}
13287836SJohn.Forte@Sun.COM 
13297836SJohn.Forte@Sun.COM 	if (svc_state == STMF_STATE_OFFLINE) {
13307836SJohn.Forte@Sun.COM 		if (std->config_state == STMF_CONFIG_INIT) {
13317836SJohn.Forte@Sun.COM 			if (std->state != STMF_STATE_OFFLINE) {
13327836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
13337836SJohn.Forte@Sun.COM 				return (EINVAL);
13347836SJohn.Forte@Sun.COM 			}
13357836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT;
13367836SJohn.Forte@Sun.COM 			stmf_delete_all_ppds();
13377836SJohn.Forte@Sun.COM 			stmf_view_clear_config();
13387836SJohn.Forte@Sun.COM 			stmf_view_init();
13397836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13407836SJohn.Forte@Sun.COM 			return (0);
13417836SJohn.Forte@Sun.COM 		}
13427836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
13437836SJohn.Forte@Sun.COM 			if (std->config_state != STMF_CONFIG_INIT_DONE) {
13447836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
13457836SJohn.Forte@Sun.COM 				return (EINVAL);
13467836SJohn.Forte@Sun.COM 			}
13477836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE;
13487836SJohn.Forte@Sun.COM 		}
13497836SJohn.Forte@Sun.COM 		if (std->state == STMF_STATE_OFFLINE) {
13507836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13517836SJohn.Forte@Sun.COM 			return (0);
13527836SJohn.Forte@Sun.COM 		}
13537836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
13547836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13557836SJohn.Forte@Sun.COM 			return (EINVAL);
13567836SJohn.Forte@Sun.COM 		}
13577836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
13587836SJohn.Forte@Sun.COM 		stmf_state.stmf_service_running = 1;
13597836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13607836SJohn.Forte@Sun.COM 
13617836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
13627836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
13637836SJohn.Forte@Sun.COM 			if (ilport->ilport_prev_state != STMF_STATE_ONLINE)
13647836SJohn.Forte@Sun.COM 				continue;
13657836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE,
13668662SJordan.Vaughan@Sun.com 			    ilport->ilport_lport, &ssi);
13677836SJohn.Forte@Sun.COM 		}
13687836SJohn.Forte@Sun.COM 
13697836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
13707836SJohn.Forte@Sun.COM 		    ilu = ilu->ilu_next) {
13717836SJohn.Forte@Sun.COM 			if (ilu->ilu_prev_state != STMF_STATE_ONLINE)
13727836SJohn.Forte@Sun.COM 				continue;
13737836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi);
13747836SJohn.Forte@Sun.COM 		}
13757836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
13767836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
13777836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13787836SJohn.Forte@Sun.COM 		return (0);
13797836SJohn.Forte@Sun.COM 	}
13807836SJohn.Forte@Sun.COM 
13817836SJohn.Forte@Sun.COM 	/* svc_state is STMF_STATE_ONLINE here */
13827836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_OFFLINE) ||
13837836SJohn.Forte@Sun.COM 	    (std->config_state == STMF_CONFIG_INIT)) {
13847836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13857836SJohn.Forte@Sun.COM 		return (EACCES);
13867836SJohn.Forte@Sun.COM 	}
13877836SJohn.Forte@Sun.COM 
13887836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 1;
13897836SJohn.Forte@Sun.COM 	stmf_state.stmf_service_running = 0;
13907836SJohn.Forte@Sun.COM 	stmf_delete_all_ppds();
13917836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
13927836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
13937836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
13947836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE)
13957836SJohn.Forte@Sun.COM 			continue;
13967836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE,
13977836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, &ssi);
13987836SJohn.Forte@Sun.COM 	}
13997836SJohn.Forte@Sun.COM 
14007836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
14017836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
14027836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE)
14037836SJohn.Forte@Sun.COM 			continue;
14047836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi);
14057836SJohn.Forte@Sun.COM 	}
14067836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14077836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 0;
14087836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14097836SJohn.Forte@Sun.COM 	return (0);
14107836SJohn.Forte@Sun.COM }
14117836SJohn.Forte@Sun.COM 
14127836SJohn.Forte@Sun.COM static int
14137836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std)
14147836SJohn.Forte@Sun.COM {
14157836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14167836SJohn.Forte@Sun.COM 	std->state = stmf_get_service_state();
14177836SJohn.Forte@Sun.COM 	std->config_state = stmf_state.stmf_config_state;
14187836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14197836SJohn.Forte@Sun.COM 
14207836SJohn.Forte@Sun.COM 	return (0);
14217836SJohn.Forte@Sun.COM }
14227836SJohn.Forte@Sun.COM 
14237836SJohn.Forte@Sun.COM typedef struct {
14247836SJohn.Forte@Sun.COM 	void	*bp;	/* back pointer from internal struct to main struct */
14257836SJohn.Forte@Sun.COM 	int	alloc_size;
14267836SJohn.Forte@Sun.COM } __istmf_t;
14277836SJohn.Forte@Sun.COM 
14287836SJohn.Forte@Sun.COM typedef struct {
14297836SJohn.Forte@Sun.COM 	__istmf_t	*fp;	/* Framework private */
14307836SJohn.Forte@Sun.COM 	void		*cp;	/* Caller private */
14317836SJohn.Forte@Sun.COM 	void		*ss;	/* struct specific */
14327836SJohn.Forte@Sun.COM } __stmf_t;
14337836SJohn.Forte@Sun.COM 
14347836SJohn.Forte@Sun.COM static struct {
14357836SJohn.Forte@Sun.COM 	int shared;
14367836SJohn.Forte@Sun.COM 	int fw_private;
14377836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 },
14387836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_provider_t),
14397836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_provider_t) },
14407836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_port_provider_t),
14417836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_port_provider_t) },
14427836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_local_port_t),
14437836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_local_port_t) },
14447836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_t),
14457836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_t) },
14467836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_scsi_session_t),
14477836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_session_t) },
14487836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(scsi_task_t),
14497836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_task_t) },
14507836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_data_buf_t),
14517836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) },
14527836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_dbuf_store_t),
14537836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) }
14547836SJohn.Forte@Sun.COM 
14557836SJohn.Forte@Sun.COM };
14567836SJohn.Forte@Sun.COM 
14577836SJohn.Forte@Sun.COM void *
14587836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
14597836SJohn.Forte@Sun.COM {
14607836SJohn.Forte@Sun.COM 	int stmf_size;
14617836SJohn.Forte@Sun.COM 	int kmem_flag;
14627836SJohn.Forte@Sun.COM 	__stmf_t *sh;
14637836SJohn.Forte@Sun.COM 
14647836SJohn.Forte@Sun.COM 	if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS))
14657836SJohn.Forte@Sun.COM 		return (NULL);
14667836SJohn.Forte@Sun.COM 
14677836SJohn.Forte@Sun.COM 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
14687836SJohn.Forte@Sun.COM 		kmem_flag = KM_NOSLEEP;
14697836SJohn.Forte@Sun.COM 	} else {
14707836SJohn.Forte@Sun.COM 		kmem_flag = KM_SLEEP;
14717836SJohn.Forte@Sun.COM 	}
14727836SJohn.Forte@Sun.COM 
14737836SJohn.Forte@Sun.COM 	additional_size = (additional_size + 7) & (~7);
14747836SJohn.Forte@Sun.COM 	stmf_size = stmf_sizes[struct_id].shared +
14758662SJordan.Vaughan@Sun.com 	    stmf_sizes[struct_id].fw_private + additional_size;
14767836SJohn.Forte@Sun.COM 
14777836SJohn.Forte@Sun.COM 	sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag);
14787836SJohn.Forte@Sun.COM 
14797836SJohn.Forte@Sun.COM 	if (sh == NULL)
14807836SJohn.Forte@Sun.COM 		return (NULL);
14817836SJohn.Forte@Sun.COM 
14829087SZhong.Wang@Sun.COM 	/*
14839087SZhong.Wang@Sun.COM 	 * In principle, the implementation inside stmf_alloc should not
14849087SZhong.Wang@Sun.COM 	 * be changed anyway. But the original order of framework private
14859087SZhong.Wang@Sun.COM 	 * data and caller private data does not support sglist in the caller
14869087SZhong.Wang@Sun.COM 	 * private data.
14879087SZhong.Wang@Sun.COM 	 * To work around this, the memory segments of framework private
14889087SZhong.Wang@Sun.COM 	 * data and caller private data are re-ordered here.
14899087SZhong.Wang@Sun.COM 	 * A better solution is to provide a specific interface to allocate
14909087SZhong.Wang@Sun.COM 	 * the sglist, then we will not need this workaround any more.
14919087SZhong.Wang@Sun.COM 	 * But before the new interface is available, the memory segment
14929087SZhong.Wang@Sun.COM 	 * ordering should be kept as is.
14939087SZhong.Wang@Sun.COM 	 */
14949087SZhong.Wang@Sun.COM 	sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
14959087SZhong.Wang@Sun.COM 	sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh,
14969087SZhong.Wang@Sun.COM 	    stmf_sizes[struct_id].shared + additional_size);
14977836SJohn.Forte@Sun.COM 
14987836SJohn.Forte@Sun.COM 	sh->fp->bp = sh;
14997836SJohn.Forte@Sun.COM 	/* Just store the total size instead of storing additional size */
15007836SJohn.Forte@Sun.COM 	sh->fp->alloc_size = stmf_size;
15017836SJohn.Forte@Sun.COM 
15027836SJohn.Forte@Sun.COM 	return (sh);
15037836SJohn.Forte@Sun.COM }
15047836SJohn.Forte@Sun.COM 
15057836SJohn.Forte@Sun.COM void
15067836SJohn.Forte@Sun.COM stmf_free(void *ptr)
15077836SJohn.Forte@Sun.COM {
15087836SJohn.Forte@Sun.COM 	__stmf_t *sh = (__stmf_t *)ptr;
15097836SJohn.Forte@Sun.COM 
15107836SJohn.Forte@Sun.COM 	/*
15117836SJohn.Forte@Sun.COM 	 * So far we dont need any struct specific processing. If such
15127836SJohn.Forte@Sun.COM 	 * a need ever arises, then store the struct id in the framework
15137836SJohn.Forte@Sun.COM 	 * private section and get it here as sh->fp->struct_id.
15147836SJohn.Forte@Sun.COM 	 */
15157836SJohn.Forte@Sun.COM 	kmem_free(ptr, sh->fp->alloc_size);
15167836SJohn.Forte@Sun.COM }
15177836SJohn.Forte@Sun.COM 
15187836SJohn.Forte@Sun.COM /*
15197836SJohn.Forte@Sun.COM  * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
15207836SJohn.Forte@Sun.COM  * framework and returns a pointer to framework private data for the lu.
15217836SJohn.Forte@Sun.COM  * Returns NULL if the lu was not found.
15227836SJohn.Forte@Sun.COM  */
15237836SJohn.Forte@Sun.COM stmf_i_lu_t *
15247836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu)
15257836SJohn.Forte@Sun.COM {
15267836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
15277836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
15287836SJohn.Forte@Sun.COM 
15297836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
15307836SJohn.Forte@Sun.COM 		if (ilu->ilu_lu == lu)
15317836SJohn.Forte@Sun.COM 			return (ilu);
15327836SJohn.Forte@Sun.COM 	}
15337836SJohn.Forte@Sun.COM 	return (NULL);
15347836SJohn.Forte@Sun.COM }
15357836SJohn.Forte@Sun.COM 
15367836SJohn.Forte@Sun.COM /*
15378818STim.Szeto@Sun.COM  * Given a pointer to stmf_local_port_t, verifies if this lport is registered
15388818STim.Szeto@Sun.COM  * with the framework and returns a pointer to framework private data for
15398818STim.Szeto@Sun.COM  * the lport.
15408818STim.Szeto@Sun.COM  * Returns NULL if the lport was not found.
15417836SJohn.Forte@Sun.COM  */
15427836SJohn.Forte@Sun.COM stmf_i_local_port_t *
15437836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport)
15447836SJohn.Forte@Sun.COM {
15457836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
15467836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
15477836SJohn.Forte@Sun.COM 
15487836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
15497836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
15507836SJohn.Forte@Sun.COM 		if (ilport->ilport_lport == lport)
15517836SJohn.Forte@Sun.COM 			return (ilport);
15527836SJohn.Forte@Sun.COM 	}
15537836SJohn.Forte@Sun.COM 	return (NULL);
15547836SJohn.Forte@Sun.COM }
15557836SJohn.Forte@Sun.COM 
15567836SJohn.Forte@Sun.COM stmf_status_t
15577836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp)
15587836SJohn.Forte@Sun.COM {
15597836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
15607836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
15617836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
15627836SJohn.Forte@Sun.COM 
15637836SJohn.Forte@Sun.COM 	if (lp->lp_lpif_rev != LPIF_REV_1)
15647836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
15657836SJohn.Forte@Sun.COM 
15667836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15677836SJohn.Forte@Sun.COM 	ilp->ilp_next = stmf_state.stmf_ilplist;
15687836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilplist = ilp;
15697836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlps++;
15707836SJohn.Forte@Sun.COM 
15717836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
15727836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
15737836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, lp->lp_name) == 0) {
15747836SJohn.Forte@Sun.COM 			break;
15757836SJohn.Forte@Sun.COM 		}
15767836SJohn.Forte@Sun.COM 	}
15777836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
15787836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
15797836SJohn.Forte@Sun.COM 	}
15807836SJohn.Forte@Sun.COM 	ilp->ilp_ppd = ppd;
15817836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ilp;
15827836SJohn.Forte@Sun.COM 	if (lp->lp_cb == NULL)
15837836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
15847836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 1;
15857836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
15867836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
15877836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
15887836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
15897836SJohn.Forte@Sun.COM 	lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
15907836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15917836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 0;
15927836SJohn.Forte@Sun.COM 
15937836SJohn.Forte@Sun.COM rlp_bail_out:
15947836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
15957836SJohn.Forte@Sun.COM 
15967836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
15977836SJohn.Forte@Sun.COM }
15987836SJohn.Forte@Sun.COM 
15997836SJohn.Forte@Sun.COM stmf_status_t
16007836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp)
16017836SJohn.Forte@Sun.COM {
16027836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t	**ppilp;
16037836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
16047836SJohn.Forte@Sun.COM 
16057836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16067836SJohn.Forte@Sun.COM 	if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) {
16077836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
16087836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
16097836SJohn.Forte@Sun.COM 	}
16107836SJohn.Forte@Sun.COM 	for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL;
16117836SJohn.Forte@Sun.COM 	    ppilp = &((*ppilp)->ilp_next)) {
16127836SJohn.Forte@Sun.COM 		if (*ppilp == ilp) {
16137836SJohn.Forte@Sun.COM 			*ppilp = ilp->ilp_next;
16147836SJohn.Forte@Sun.COM 			stmf_state.stmf_nlps--;
16157836SJohn.Forte@Sun.COM 			if (ilp->ilp_ppd) {
16167836SJohn.Forte@Sun.COM 				ilp->ilp_ppd->ppd_provider = NULL;
16177836SJohn.Forte@Sun.COM 				ilp->ilp_ppd = NULL;
16187836SJohn.Forte@Sun.COM 			}
16197836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
16207836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
16217836SJohn.Forte@Sun.COM 		}
16227836SJohn.Forte@Sun.COM 	}
16237836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16247836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
16257836SJohn.Forte@Sun.COM }
16267836SJohn.Forte@Sun.COM 
16277836SJohn.Forte@Sun.COM stmf_status_t
16287836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp)
16297836SJohn.Forte@Sun.COM {
16307836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
16317836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
16327836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
16337836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
16347836SJohn.Forte@Sun.COM 
16357836SJohn.Forte@Sun.COM 	if (pp->pp_portif_rev != PORTIF_REV_1)
16367836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
16377836SJohn.Forte@Sun.COM 
16387836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16397836SJohn.Forte@Sun.COM 	ipp->ipp_next = stmf_state.stmf_ipplist;
16407836SJohn.Forte@Sun.COM 	stmf_state.stmf_ipplist = ipp;
16417836SJohn.Forte@Sun.COM 	stmf_state.stmf_npps++;
16427836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
16437836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
16447836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, pp->pp_name) == 0) {
16457836SJohn.Forte@Sun.COM 			break;
16467836SJohn.Forte@Sun.COM 		}
16477836SJohn.Forte@Sun.COM 	}
16487836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
16497836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
16507836SJohn.Forte@Sun.COM 	}
16517836SJohn.Forte@Sun.COM 	ipp->ipp_ppd = ppd;
16527836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ipp;
16537836SJohn.Forte@Sun.COM 	if (pp->pp_cb == NULL)
16547836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
16557836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 1;
16567836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
16577836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
16587836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
16597836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16607836SJohn.Forte@Sun.COM 	pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
16617836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16627836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 0;
16637836SJohn.Forte@Sun.COM 
16647836SJohn.Forte@Sun.COM rpp_bail_out:
16657836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16667836SJohn.Forte@Sun.COM 
16677836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
16687836SJohn.Forte@Sun.COM }
16697836SJohn.Forte@Sun.COM 
16707836SJohn.Forte@Sun.COM stmf_status_t
16717836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp)
16727836SJohn.Forte@Sun.COM {
16737836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
16747836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
16757836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t **ppipp;
16767836SJohn.Forte@Sun.COM 
16777836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16787836SJohn.Forte@Sun.COM 	if (ipp->ipp_npps || ipp->ipp_cb_in_progress) {
16797836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
16807836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
16817836SJohn.Forte@Sun.COM 	}
16827836SJohn.Forte@Sun.COM 	for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL;
16837836SJohn.Forte@Sun.COM 	    ppipp = &((*ppipp)->ipp_next)) {
16847836SJohn.Forte@Sun.COM 		if (*ppipp == ipp) {
16857836SJohn.Forte@Sun.COM 			*ppipp = ipp->ipp_next;
16867836SJohn.Forte@Sun.COM 			stmf_state.stmf_npps--;
16877836SJohn.Forte@Sun.COM 			if (ipp->ipp_ppd) {
16887836SJohn.Forte@Sun.COM 				ipp->ipp_ppd->ppd_provider = NULL;
16897836SJohn.Forte@Sun.COM 				ipp->ipp_ppd = NULL;
16907836SJohn.Forte@Sun.COM 			}
16917836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
16927836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
16937836SJohn.Forte@Sun.COM 		}
16947836SJohn.Forte@Sun.COM 	}
16957836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16967836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
16977836SJohn.Forte@Sun.COM }
16987836SJohn.Forte@Sun.COM 
16997836SJohn.Forte@Sun.COM int
17009585STim.Szeto@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
17019585STim.Szeto@Sun.COM     uint32_t *err_ret)
17027836SJohn.Forte@Sun.COM {
17037836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t		*ipp;
17047836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t		*ilp;
17057836SJohn.Forte@Sun.COM 	stmf_pp_data_t			*ppd;
17067836SJohn.Forte@Sun.COM 	nvlist_t			*nv;
17077836SJohn.Forte@Sun.COM 	int				s;
17087836SJohn.Forte@Sun.COM 	int				ret;
17097836SJohn.Forte@Sun.COM 
17109585STim.Szeto@Sun.COM 	*err_ret = 0;
17119585STim.Szeto@Sun.COM 
17127836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
17137836SJohn.Forte@Sun.COM 		return (EINVAL);
17147836SJohn.Forte@Sun.COM 	}
17157836SJohn.Forte@Sun.COM 
17167836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
17177836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
17187836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
17197836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
17207836SJohn.Forte@Sun.COM 				continue;
17217836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
17227836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
17237836SJohn.Forte@Sun.COM 				continue;
17247836SJohn.Forte@Sun.COM 		}
17257836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
17267836SJohn.Forte@Sun.COM 			break;
17277836SJohn.Forte@Sun.COM 	}
17287836SJohn.Forte@Sun.COM 
17297836SJohn.Forte@Sun.COM 	if (ppd == NULL) {
17307836SJohn.Forte@Sun.COM 		/* New provider */
17317836SJohn.Forte@Sun.COM 		s = strlen(ppi->ppi_name);
17327836SJohn.Forte@Sun.COM 		if (s > 254) {
17337836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17347836SJohn.Forte@Sun.COM 			return (EINVAL);
17357836SJohn.Forte@Sun.COM 		}
17367836SJohn.Forte@Sun.COM 		s += sizeof (stmf_pp_data_t) - 7;
17377836SJohn.Forte@Sun.COM 
17387836SJohn.Forte@Sun.COM 		ppd = kmem_zalloc(s, KM_NOSLEEP);
17397836SJohn.Forte@Sun.COM 		if (ppd == NULL) {
17407836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17417836SJohn.Forte@Sun.COM 			return (ENOMEM);
17427836SJohn.Forte@Sun.COM 		}
17437836SJohn.Forte@Sun.COM 		ppd->ppd_alloc_size = s;
17447836SJohn.Forte@Sun.COM 		(void) strcpy(ppd->ppd_name, ppi->ppi_name);
17457836SJohn.Forte@Sun.COM 
17467836SJohn.Forte@Sun.COM 		/* See if this provider already exists */
17477836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
17487836SJohn.Forte@Sun.COM 			ppd->ppd_lu_provider = 1;
17497836SJohn.Forte@Sun.COM 			for (ilp = stmf_state.stmf_ilplist; ilp != NULL;
17507836SJohn.Forte@Sun.COM 			    ilp = ilp->ilp_next) {
17517836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
17527836SJohn.Forte@Sun.COM 				    ilp->ilp_lp->lp_name) == 0) {
17537836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ilp;
17547836SJohn.Forte@Sun.COM 					ilp->ilp_ppd = ppd;
17557836SJohn.Forte@Sun.COM 					break;
17567836SJohn.Forte@Sun.COM 				}
17577836SJohn.Forte@Sun.COM 			}
17587836SJohn.Forte@Sun.COM 		} else {
17597836SJohn.Forte@Sun.COM 			ppd->ppd_port_provider = 1;
17607836SJohn.Forte@Sun.COM 			for (ipp = stmf_state.stmf_ipplist; ipp != NULL;
17617836SJohn.Forte@Sun.COM 			    ipp = ipp->ipp_next) {
17627836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
17637836SJohn.Forte@Sun.COM 				    ipp->ipp_pp->pp_name) == 0) {
17647836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ipp;
17657836SJohn.Forte@Sun.COM 					ipp->ipp_ppd = ppd;
17667836SJohn.Forte@Sun.COM 					break;
17677836SJohn.Forte@Sun.COM 				}
17687836SJohn.Forte@Sun.COM 			}
17697836SJohn.Forte@Sun.COM 		}
17707836SJohn.Forte@Sun.COM 
17717836SJohn.Forte@Sun.COM 		/* Link this ppd in */
17727836SJohn.Forte@Sun.COM 		ppd->ppd_next = stmf_state.stmf_ppdlist;
17737836SJohn.Forte@Sun.COM 		stmf_state.stmf_ppdlist = ppd;
17747836SJohn.Forte@Sun.COM 	}
17757836SJohn.Forte@Sun.COM 
17769585STim.Szeto@Sun.COM 	/*
17779585STim.Szeto@Sun.COM 	 * User is requesting that the token be checked.
17789585STim.Szeto@Sun.COM 	 * If there was another set after the user's get
17799585STim.Szeto@Sun.COM 	 * it's an error
17809585STim.Szeto@Sun.COM 	 */
17819585STim.Szeto@Sun.COM 	if (ppi->ppi_token_valid) {
17829585STim.Szeto@Sun.COM 		if (ppi->ppi_token != ppd->ppd_token) {
17839585STim.Szeto@Sun.COM 			*err_ret = STMF_IOCERR_PPD_UPDATED;
17849585STim.Szeto@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17859585STim.Szeto@Sun.COM 			return (EINVAL);
17869585STim.Szeto@Sun.COM 		}
17879585STim.Szeto@Sun.COM 	}
17889585STim.Szeto@Sun.COM 
17897836SJohn.Forte@Sun.COM 	if ((ret = nvlist_unpack((char *)ppi->ppi_data,
17907836SJohn.Forte@Sun.COM 	    (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
17917836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
17927836SJohn.Forte@Sun.COM 		return (ret);
17937836SJohn.Forte@Sun.COM 	}
17947836SJohn.Forte@Sun.COM 
17957836SJohn.Forte@Sun.COM 	/* Free any existing lists and add this one to the ppd */
17967836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
17977836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
17987836SJohn.Forte@Sun.COM 	ppd->ppd_nv = nv;
17997836SJohn.Forte@Sun.COM 
18009585STim.Szeto@Sun.COM 	/* set the token for writes */
18019585STim.Szeto@Sun.COM 	ppd->ppd_token++;
18029585STim.Szeto@Sun.COM 	/* return token to caller */
18039585STim.Szeto@Sun.COM 	if (ppi_token) {
18049585STim.Szeto@Sun.COM 		*ppi_token = ppd->ppd_token;
18059585STim.Szeto@Sun.COM 	}
18069585STim.Szeto@Sun.COM 
18077836SJohn.Forte@Sun.COM 	/* If there is a provider registered, do the notifications */
18087836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
18097836SJohn.Forte@Sun.COM 		uint32_t cb_flags = 0;
18107836SJohn.Forte@Sun.COM 
18117836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
18127836SJohn.Forte@Sun.COM 			cb_flags |= STMF_PCB_STMF_ONLINING;
18137836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
18147836SJohn.Forte@Sun.COM 			ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider;
18157836SJohn.Forte@Sun.COM 			if (ilp->ilp_lp->lp_cb == NULL)
18167836SJohn.Forte@Sun.COM 				goto bail_out;
18177836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 1;
18187836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
18197836SJohn.Forte@Sun.COM 			ilp->ilp_lp->lp_cb(ilp->ilp_lp,
18207836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
18217836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
18227836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 0;
18237836SJohn.Forte@Sun.COM 		} else {
18247836SJohn.Forte@Sun.COM 			ipp = (stmf_i_port_provider_t *)ppd->ppd_provider;
18257836SJohn.Forte@Sun.COM 			if (ipp->ipp_pp->pp_cb == NULL)
18267836SJohn.Forte@Sun.COM 				goto bail_out;
18277836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 1;
18287836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
18297836SJohn.Forte@Sun.COM 			ipp->ipp_pp->pp_cb(ipp->ipp_pp,
18307836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
18317836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
18327836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 0;
18337836SJohn.Forte@Sun.COM 		}
18347836SJohn.Forte@Sun.COM 	}
18357836SJohn.Forte@Sun.COM 
18367836SJohn.Forte@Sun.COM bail_out:
18377836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
18387836SJohn.Forte@Sun.COM 
18397836SJohn.Forte@Sun.COM 	return (0);
18407836SJohn.Forte@Sun.COM }
18417836SJohn.Forte@Sun.COM 
18427836SJohn.Forte@Sun.COM void
18437836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd)
18447836SJohn.Forte@Sun.COM {
18457836SJohn.Forte@Sun.COM 	stmf_pp_data_t **pppd;
18467836SJohn.Forte@Sun.COM 
18477836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
18487836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
18497836SJohn.Forte@Sun.COM 		if (ppd->ppd_lu_provider) {
18507836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
18517836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ilp_ppd = NULL;
18527836SJohn.Forte@Sun.COM 		} else {
18537836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
18547836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ipp_ppd = NULL;
18557836SJohn.Forte@Sun.COM 		}
18567836SJohn.Forte@Sun.COM 		ppd->ppd_provider = NULL;
18577836SJohn.Forte@Sun.COM 	}
18587836SJohn.Forte@Sun.COM 
18597836SJohn.Forte@Sun.COM 	for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL;
18608662SJordan.Vaughan@Sun.com 	    pppd = &((*pppd)->ppd_next)) {
18617836SJohn.Forte@Sun.COM 		if (*pppd == ppd)
18627836SJohn.Forte@Sun.COM 			break;
18637836SJohn.Forte@Sun.COM 	}
18647836SJohn.Forte@Sun.COM 
18657836SJohn.Forte@Sun.COM 	if (*pppd == NULL)
18667836SJohn.Forte@Sun.COM 		return;
18677836SJohn.Forte@Sun.COM 
18687836SJohn.Forte@Sun.COM 	*pppd = ppd->ppd_next;
18697836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
18707836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
18717836SJohn.Forte@Sun.COM 
18727836SJohn.Forte@Sun.COM 	kmem_free(ppd, ppd->ppd_alloc_size);
18737836SJohn.Forte@Sun.COM }
18747836SJohn.Forte@Sun.COM 
18757836SJohn.Forte@Sun.COM int
18767836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
18777836SJohn.Forte@Sun.COM {
18787836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
18797836SJohn.Forte@Sun.COM 	int ret = ENOENT;
18807836SJohn.Forte@Sun.COM 
18817836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
18827836SJohn.Forte@Sun.COM 		return (EINVAL);
18837836SJohn.Forte@Sun.COM 	}
18847836SJohn.Forte@Sun.COM 
18857836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
18867836SJohn.Forte@Sun.COM 
18877836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
18887836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
18897836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
18907836SJohn.Forte@Sun.COM 				continue;
18917836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
18927836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
18937836SJohn.Forte@Sun.COM 				continue;
18947836SJohn.Forte@Sun.COM 		}
18957836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
18967836SJohn.Forte@Sun.COM 			break;
18977836SJohn.Forte@Sun.COM 	}
18987836SJohn.Forte@Sun.COM 
18997836SJohn.Forte@Sun.COM 	if (ppd) {
19007836SJohn.Forte@Sun.COM 		ret = 0;
19017836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
19027836SJohn.Forte@Sun.COM 	}
19037836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
19047836SJohn.Forte@Sun.COM 
19057836SJohn.Forte@Sun.COM 	return (ret);
19067836SJohn.Forte@Sun.COM }
19077836SJohn.Forte@Sun.COM 
19089585STim.Szeto@Sun.COM int
19099585STim.Szeto@Sun.COM stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
19109585STim.Szeto@Sun.COM     uint32_t *err_ret)
19119585STim.Szeto@Sun.COM {
19129585STim.Szeto@Sun.COM 	stmf_pp_data_t *ppd;
19139585STim.Szeto@Sun.COM 	size_t req_size;
19149585STim.Szeto@Sun.COM 	int ret = ENOENT;
19159585STim.Szeto@Sun.COM 	char *bufp = (char *)ppi_out->ppi_data;
19169585STim.Szeto@Sun.COM 
19179585STim.Szeto@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
19189585STim.Szeto@Sun.COM 		return (EINVAL);
19199585STim.Szeto@Sun.COM 	}
19209585STim.Szeto@Sun.COM 
19219585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
19229585STim.Szeto@Sun.COM 
19239585STim.Szeto@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
19249585STim.Szeto@Sun.COM 		if (ppi->ppi_lu_provider) {
19259585STim.Szeto@Sun.COM 			if (!ppd->ppd_lu_provider)
19269585STim.Szeto@Sun.COM 				continue;
19279585STim.Szeto@Sun.COM 		} else if (ppi->ppi_port_provider) {
19289585STim.Szeto@Sun.COM 			if (!ppd->ppd_port_provider)
19299585STim.Szeto@Sun.COM 				continue;
19309585STim.Szeto@Sun.COM 		}
19319585STim.Szeto@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
19329585STim.Szeto@Sun.COM 			break;
19339585STim.Szeto@Sun.COM 	}
19349585STim.Szeto@Sun.COM 
19359585STim.Szeto@Sun.COM 	if (ppd && ppd->ppd_nv) {
19369585STim.Szeto@Sun.COM 		ppi_out->ppi_token = ppd->ppd_token;
19379585STim.Szeto@Sun.COM 		if ((ret = nvlist_size(ppd->ppd_nv, &req_size,
19389585STim.Szeto@Sun.COM 		    NV_ENCODE_XDR)) != 0) {
19399585STim.Szeto@Sun.COM 			goto done;
19409585STim.Szeto@Sun.COM 		}
19419585STim.Szeto@Sun.COM 		ppi_out->ppi_data_size = req_size;
19429585STim.Szeto@Sun.COM 		if (req_size > ppi->ppi_data_size) {
19439585STim.Szeto@Sun.COM 			*err_ret = STMF_IOCERR_INSUFFICIENT_BUF;
19449585STim.Szeto@Sun.COM 			ret = EINVAL;
19459585STim.Szeto@Sun.COM 			goto done;
19469585STim.Szeto@Sun.COM 		}
19479585STim.Szeto@Sun.COM 
19489585STim.Szeto@Sun.COM 		if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size,
19499585STim.Szeto@Sun.COM 		    NV_ENCODE_XDR, 0)) != 0) {
19509585STim.Szeto@Sun.COM 			goto done;
19519585STim.Szeto@Sun.COM 		}
19529585STim.Szeto@Sun.COM 		ret = 0;
19539585STim.Szeto@Sun.COM 	}
19549585STim.Szeto@Sun.COM 
19559585STim.Szeto@Sun.COM done:
19569585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
19579585STim.Szeto@Sun.COM 
19589585STim.Szeto@Sun.COM 	return (ret);
19599585STim.Szeto@Sun.COM }
19609585STim.Szeto@Sun.COM 
19617836SJohn.Forte@Sun.COM void
19627836SJohn.Forte@Sun.COM stmf_delete_all_ppds()
19637836SJohn.Forte@Sun.COM {
19647836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd, *nppd;
19657836SJohn.Forte@Sun.COM 
19667836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
19677836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) {
19687836SJohn.Forte@Sun.COM 		nppd = ppd->ppd_next;
19697836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
19707836SJohn.Forte@Sun.COM 	}
19717836SJohn.Forte@Sun.COM }
19727836SJohn.Forte@Sun.COM 
19739435STim.Szeto@Sun.COM /*
19749435STim.Szeto@Sun.COM  * 16 is the max string length of a protocol_ident, increase
19759435STim.Szeto@Sun.COM  * the size if needed.
19769435STim.Szeto@Sun.COM  */
19779435STim.Szeto@Sun.COM #define	STMF_KSTAT_LU_SZ	(STMF_GUID_INPUT + 1 + 256)
19789435STim.Szeto@Sun.COM #define	STMF_KSTAT_TGT_SZ	(256 * 2 + 16)
19799435STim.Szeto@Sun.COM 
19809435STim.Szeto@Sun.COM typedef struct stmf_kstat_lu_info {
19819435STim.Szeto@Sun.COM 	kstat_named_t		i_lun_guid;
19829435STim.Szeto@Sun.COM 	kstat_named_t		i_lun_alias;
19839435STim.Szeto@Sun.COM } stmf_kstat_lu_info_t;
19849435STim.Szeto@Sun.COM 
19859435STim.Szeto@Sun.COM typedef struct stmf_kstat_tgt_info {
19869435STim.Szeto@Sun.COM 	kstat_named_t		i_tgt_name;
19879435STim.Szeto@Sun.COM 	kstat_named_t		i_tgt_alias;
19889435STim.Szeto@Sun.COM 	kstat_named_t		i_protocol;
19899435STim.Szeto@Sun.COM } stmf_kstat_tgt_info_t;
19909435STim.Szeto@Sun.COM 
19919435STim.Szeto@Sun.COM /*
19929435STim.Szeto@Sun.COM  * This array matches the Protocol Identifier in stmf_ioctl.h
19939435STim.Szeto@Sun.COM  */
19949435STim.Szeto@Sun.COM char *protocol_ident[PROTOCOL_ANY] = {
19959435STim.Szeto@Sun.COM 	"Fibre Channel",
19969435STim.Szeto@Sun.COM 	"Parallel SCSI",
19979435STim.Szeto@Sun.COM 	"SSA",
19989435STim.Szeto@Sun.COM 	"IEEE_1394",
19999435STim.Szeto@Sun.COM 	"SRP",
20009435STim.Szeto@Sun.COM 	"iSCSI",
20019435STim.Szeto@Sun.COM 	"SAS",
20029435STim.Szeto@Sun.COM 	"ADT",
20039435STim.Szeto@Sun.COM 	"ATAPI",
20049435STim.Szeto@Sun.COM 	"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"
20059435STim.Szeto@Sun.COM };
20069435STim.Szeto@Sun.COM 
20079435STim.Szeto@Sun.COM /*
20089435STim.Szeto@Sun.COM  * Update the lun wait/run queue count
20099435STim.Szeto@Sun.COM  */
20109435STim.Szeto@Sun.COM static void
20119435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(scsi_task_t *task, void func())
20129435STim.Szeto@Sun.COM {
20139435STim.Szeto@Sun.COM 	stmf_i_lu_t		*ilu;
20149435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20159435STim.Szeto@Sun.COM 
20169435STim.Szeto@Sun.COM 	if (task->task_lu == dlun0)
20179435STim.Szeto@Sun.COM 		return;
20189435STim.Szeto@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
20199435STim.Szeto@Sun.COM 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
20209435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
20219435STim.Szeto@Sun.COM 		if (kip != NULL) {
20229435STim.Szeto@Sun.COM 			mutex_enter(ilu->ilu_kstat_io->ks_lock);
20239435STim.Szeto@Sun.COM 			func(kip);
20249435STim.Szeto@Sun.COM 			mutex_exit(ilu->ilu_kstat_io->ks_lock);
20259435STim.Szeto@Sun.COM 		}
20269435STim.Szeto@Sun.COM 	}
20279435STim.Szeto@Sun.COM }
20289435STim.Szeto@Sun.COM 
20299435STim.Szeto@Sun.COM /*
20309435STim.Szeto@Sun.COM  * Update the target(lport) wait/run queue count
20319435STim.Szeto@Sun.COM  */
20329435STim.Szeto@Sun.COM static void
20339435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(scsi_task_t *task, void func())
20349435STim.Szeto@Sun.COM {
20359435STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilp;
20369435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20379435STim.Szeto@Sun.COM 
20389435STim.Szeto@Sun.COM 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
20399435STim.Szeto@Sun.COM 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
20409435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
20419435STim.Szeto@Sun.COM 		if (kip != NULL) {
20429435STim.Szeto@Sun.COM 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
20439435STim.Szeto@Sun.COM 			func(kip);
20449435STim.Szeto@Sun.COM 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
20459435STim.Szeto@Sun.COM 		}
20469435STim.Szeto@Sun.COM 	}
20479435STim.Szeto@Sun.COM }
20489435STim.Szeto@Sun.COM 
20499435STim.Szeto@Sun.COM static void
20509435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
20519435STim.Szeto@Sun.COM {
20529435STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilp;
20539435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20549435STim.Szeto@Sun.COM 
20559435STim.Szeto@Sun.COM 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
20569435STim.Szeto@Sun.COM 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
20579435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
20589435STim.Szeto@Sun.COM 		if (kip != NULL) {
20599435STim.Szeto@Sun.COM 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
20609435STim.Szeto@Sun.COM 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
20619435STim.Szeto@Sun.COM 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
20629435STim.Szeto@Sun.COM 		}
20639435STim.Szeto@Sun.COM 	}
20649435STim.Szeto@Sun.COM }
20659435STim.Szeto@Sun.COM 
20669435STim.Szeto@Sun.COM static void
20679435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
20689435STim.Szeto@Sun.COM {
20699435STim.Szeto@Sun.COM 	stmf_i_lu_t		*ilu;
20709435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20719435STim.Szeto@Sun.COM 
20729435STim.Szeto@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
20739435STim.Szeto@Sun.COM 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
20749435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
20759435STim.Szeto@Sun.COM 		if (kip != NULL) {
20769435STim.Szeto@Sun.COM 			mutex_enter(ilu->ilu_kstat_io->ks_lock);
20779435STim.Szeto@Sun.COM 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
20789435STim.Szeto@Sun.COM 			mutex_exit(ilu->ilu_kstat_io->ks_lock);
20799435STim.Szeto@Sun.COM 		}
20809435STim.Szeto@Sun.COM 	}
20819435STim.Szeto@Sun.COM }
20829435STim.Szeto@Sun.COM 
20839435STim.Szeto@Sun.COM static void
20849435STim.Szeto@Sun.COM stmf_create_kstat_lu(stmf_i_lu_t *ilu)
20859435STim.Szeto@Sun.COM {
20869435STim.Szeto@Sun.COM 	char				ks_nm[KSTAT_STRLEN];
20879435STim.Szeto@Sun.COM 	stmf_kstat_lu_info_t		*ks_lu;
20889435STim.Szeto@Sun.COM 
20899435STim.Szeto@Sun.COM 	/* create kstat lun info */
20909435STim.Szeto@Sun.COM 	ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ,
20919435STim.Szeto@Sun.COM 	    KM_NOSLEEP);
20929435STim.Szeto@Sun.COM 	if (ks_lu == NULL) {
20939435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
20949435STim.Szeto@Sun.COM 		return;
20959435STim.Szeto@Sun.COM 	}
20969435STim.Szeto@Sun.COM 
20979435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
20989435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu);
20999435STim.Szeto@Sun.COM 	if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0,
21009435STim.Szeto@Sun.COM 	    ks_nm, "misc", KSTAT_TYPE_NAMED,
21019435STim.Szeto@Sun.COM 	    sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t),
21029435STim.Szeto@Sun.COM 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
21039435STim.Szeto@Sun.COM 		kmem_free(ks_lu, STMF_KSTAT_LU_SZ);
21049435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create lu failed");
21059435STim.Szeto@Sun.COM 		return;
21069435STim.Szeto@Sun.COM 	}
21079435STim.Szeto@Sun.COM 
21089435STim.Szeto@Sun.COM 	ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ;
21099435STim.Szeto@Sun.COM 	ilu->ilu_kstat_info->ks_data = ks_lu;
21109435STim.Szeto@Sun.COM 
21119435STim.Szeto@Sun.COM 	kstat_named_init(&ks_lu->i_lun_guid, "lun-guid",
21129435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21139435STim.Szeto@Sun.COM 	kstat_named_init(&ks_lu->i_lun_alias, "lun-alias",
21149435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21159435STim.Szeto@Sun.COM 
21169435STim.Szeto@Sun.COM 	/* convert guid to hex string */
21179435STim.Szeto@Sun.COM 	int		i;
21189435STim.Szeto@Sun.COM 	uint8_t		*p = ilu->ilu_lu->lu_id->ident;
21199435STim.Szeto@Sun.COM 	bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid));
21209435STim.Szeto@Sun.COM 	for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
21219435STim.Szeto@Sun.COM 		(void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]);
21229435STim.Szeto@Sun.COM 	}
21239435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_lu->i_lun_guid,
21249435STim.Szeto@Sun.COM 	    (const char *)ilu->ilu_ascii_hex_guid);
21259435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_lu->i_lun_alias,
21269435STim.Szeto@Sun.COM 	    (const char *)ilu->ilu_lu->lu_alias);
21279435STim.Szeto@Sun.COM 	kstat_install(ilu->ilu_kstat_info);
21289435STim.Szeto@Sun.COM 
21299435STim.Szeto@Sun.COM 	/* create kstat lun io */
21309435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21319435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu);
21329435STim.Szeto@Sun.COM 	if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
21339435STim.Szeto@Sun.COM 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
21349435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create lu_io failed");
21359435STim.Szeto@Sun.COM 		return;
21369435STim.Szeto@Sun.COM 	}
21379435STim.Szeto@Sun.COM 	mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0);
21389435STim.Szeto@Sun.COM 	ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock;
21399435STim.Szeto@Sun.COM 	kstat_install(ilu->ilu_kstat_io);
21409435STim.Szeto@Sun.COM }
21419435STim.Szeto@Sun.COM 
21429435STim.Szeto@Sun.COM static void
21439435STim.Szeto@Sun.COM stmf_create_kstat_lport(stmf_i_local_port_t *ilport)
21449435STim.Szeto@Sun.COM {
21459435STim.Szeto@Sun.COM 	char				ks_nm[KSTAT_STRLEN];
21469435STim.Szeto@Sun.COM 	stmf_kstat_tgt_info_t		*ks_tgt;
21479435STim.Szeto@Sun.COM 	int				id, len;
21489435STim.Szeto@Sun.COM 
21499435STim.Szeto@Sun.COM 	/* create kstat lport info */
21509435STim.Szeto@Sun.COM 	ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ,
21519435STim.Szeto@Sun.COM 	    KM_NOSLEEP);
21529435STim.Szeto@Sun.COM 	if (ks_tgt == NULL) {
21539435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
21549435STim.Szeto@Sun.COM 		return;
21559435STim.Szeto@Sun.COM 	}
21569435STim.Szeto@Sun.COM 
21579435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21589435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport);
21599435STim.Szeto@Sun.COM 	if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME,
21609435STim.Szeto@Sun.COM 	    0, ks_nm, "misc", KSTAT_TYPE_NAMED,
21619435STim.Szeto@Sun.COM 	    sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t),
21629435STim.Szeto@Sun.COM 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
21639435STim.Szeto@Sun.COM 		kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ);
21649435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create target failed");
21659435STim.Szeto@Sun.COM 		return;
21669435STim.Szeto@Sun.COM 	}
21679435STim.Szeto@Sun.COM 
21689435STim.Szeto@Sun.COM 	ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ;
21699435STim.Szeto@Sun.COM 	ilport->ilport_kstat_info->ks_data = ks_tgt;
21709435STim.Szeto@Sun.COM 
21719435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_tgt_name, "target-name",
21729435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21739435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias",
21749435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21759435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_protocol, "protocol",
21769435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21779435STim.Szeto@Sun.COM 
21789435STim.Szeto@Sun.COM 	/* ident might not be null terminated */
21799435STim.Szeto@Sun.COM 	len = ilport->ilport_lport->lport_id->ident_length;
21809435STim.Szeto@Sun.COM 	bcopy(ilport->ilport_lport->lport_id->ident,
21819435STim.Szeto@Sun.COM 	    ilport->ilport_kstat_tgt_name, len);
21829435STim.Szeto@Sun.COM 	ilport->ilport_kstat_tgt_name[len + 1] = NULL;
21839435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_tgt_name,
21849435STim.Szeto@Sun.COM 	    (const char *)ilport->ilport_kstat_tgt_name);
21859435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_tgt_alias,
21869435STim.Szeto@Sun.COM 	    (const char *)ilport->ilport_lport->lport_alias);
21879435STim.Szeto@Sun.COM 	/* protocol */
21889435STim.Szeto@Sun.COM 	if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) {
21899435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: protocol_id out of bound");
21909435STim.Szeto@Sun.COM 		id = PROTOCOL_ANY;
21919435STim.Szeto@Sun.COM 	}
21929435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]);
21939435STim.Szeto@Sun.COM 	kstat_install(ilport->ilport_kstat_info);
21949435STim.Szeto@Sun.COM 
21959435STim.Szeto@Sun.COM 	/* create kstat lport io */
21969435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21979435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport);
21989435STim.Szeto@Sun.COM 	if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
21999435STim.Szeto@Sun.COM 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
22009435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create target_io failed");
22019435STim.Szeto@Sun.COM 		return;
22029435STim.Szeto@Sun.COM 	}
22039435STim.Szeto@Sun.COM 	mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0);
22049435STim.Szeto@Sun.COM 	ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock;
22059435STim.Szeto@Sun.COM 	kstat_install(ilport->ilport_kstat_io);
22069435STim.Szeto@Sun.COM }
22079435STim.Szeto@Sun.COM 
22087836SJohn.Forte@Sun.COM stmf_status_t
22097836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu)
22107836SJohn.Forte@Sun.COM {
22117836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
22127836SJohn.Forte@Sun.COM 	uint8_t *p1, *p2;
22137836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
22147836SJohn.Forte@Sun.COM 	stmf_id_data_t *luid;
22157836SJohn.Forte@Sun.COM 
22167836SJohn.Forte@Sun.COM 	if ((lu->lu_id->ident_type != ID_TYPE_NAA) ||
22177836SJohn.Forte@Sun.COM 	    (lu->lu_id->ident_length != 16) ||
22187836SJohn.Forte@Sun.COM 	    ((lu->lu_id->ident[0] & 0xf0) != 0x60)) {
22197836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
22207836SJohn.Forte@Sun.COM 	}
22217836SJohn.Forte@Sun.COM 	p1 = &lu->lu_id->ident[0];
22227836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
22237836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
22247836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
22257836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
22267836SJohn.Forte@Sun.COM 	}
22277836SJohn.Forte@Sun.COM 
22287836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
22297836SJohn.Forte@Sun.COM 		p2 = &ilu->ilu_lu->lu_id->ident[0];
22307836SJohn.Forte@Sun.COM 		if (bcmp(p1, p2, 16) == 0) {
22317836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
22327836SJohn.Forte@Sun.COM 			return (STMF_ALREADY);
22337836SJohn.Forte@Sun.COM 		}
22347836SJohn.Forte@Sun.COM 	}
22357836SJohn.Forte@Sun.COM 
22367836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
22377836SJohn.Forte@Sun.COM 	luid = stmf_lookup_id(&stmf_state.stmf_luid_list,
22387836SJohn.Forte@Sun.COM 	    lu->lu_id->ident_length, lu->lu_id->ident);
22397836SJohn.Forte@Sun.COM 	if (luid) {
22407836SJohn.Forte@Sun.COM 		luid->id_pt_to_object = (void *)ilu;
22417836SJohn.Forte@Sun.COM 		ilu->ilu_luid = luid;
22427836SJohn.Forte@Sun.COM 	}
22437836SJohn.Forte@Sun.COM 	ilu->ilu_alias = NULL;
22447836SJohn.Forte@Sun.COM 
22457836SJohn.Forte@Sun.COM 	ilu->ilu_next = stmf_state.stmf_ilulist;
22467836SJohn.Forte@Sun.COM 	ilu->ilu_prev = NULL;
22477836SJohn.Forte@Sun.COM 	if (ilu->ilu_next)
22487836SJohn.Forte@Sun.COM 		ilu->ilu_next->ilu_prev = ilu;
22497836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilulist = ilu;
22507836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlus++;
22517836SJohn.Forte@Sun.COM 	if (lu->lu_lp) {
22527836SJohn.Forte@Sun.COM 		((stmf_i_lu_provider_t *)
22537836SJohn.Forte@Sun.COM 		    (lu->lu_lp->lp_stmf_private))->ilp_nlus++;
22547836SJohn.Forte@Sun.COM 	}
22557836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
22567836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
22579435STim.Szeto@Sun.COM 	stmf_create_kstat_lu(ilu);
22587836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
22597836SJohn.Forte@Sun.COM 
22607836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lu can be brought online */
22617836SJohn.Forte@Sun.COM 	ilu->ilu_prev_state = STMF_STATE_ONLINE;
22627836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
22637836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
22647836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
22657836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci);
22667836SJohn.Forte@Sun.COM 	}
22677836SJohn.Forte@Sun.COM 
22687836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
22697836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
22707836SJohn.Forte@Sun.COM }
22717836SJohn.Forte@Sun.COM 
22727836SJohn.Forte@Sun.COM stmf_status_t
22737836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu)
22747836SJohn.Forte@Sun.COM {
22757836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
22767836SJohn.Forte@Sun.COM 
22777836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
22787836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
22797836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
22807836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
22817836SJohn.Forte@Sun.COM 	}
22827836SJohn.Forte@Sun.COM 	ilu = stmf_lookup_lu(lu);
22837836SJohn.Forte@Sun.COM 	if (ilu == NULL) {
22847836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
22857836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
22867836SJohn.Forte@Sun.COM 	}
22877836SJohn.Forte@Sun.COM 	if (ilu->ilu_state == STMF_STATE_OFFLINE) {
22887836SJohn.Forte@Sun.COM 		ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
22897836SJohn.Forte@Sun.COM 		while (ilu->ilu_flags & ILU_STALL_DEREGISTER) {
22907836SJohn.Forte@Sun.COM 			cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock);
22917836SJohn.Forte@Sun.COM 		}
22927836SJohn.Forte@Sun.COM 		if (ilu->ilu_ntasks) {
22937836SJohn.Forte@Sun.COM 			stmf_i_scsi_task_t *itask, *nitask;
22947836SJohn.Forte@Sun.COM 
22957836SJohn.Forte@Sun.COM 			nitask = ilu->ilu_tasks;
22967836SJohn.Forte@Sun.COM 			do {
22977836SJohn.Forte@Sun.COM 				itask = nitask;
22987836SJohn.Forte@Sun.COM 				nitask = itask->itask_lu_next;
22997836SJohn.Forte@Sun.COM 				lu->lu_task_free(itask->itask_task);
23007836SJohn.Forte@Sun.COM 				stmf_free(itask->itask_task);
23017836SJohn.Forte@Sun.COM 			} while (nitask != NULL);
23027836SJohn.Forte@Sun.COM 
23037836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = ilu->ilu_free_tasks = NULL;
23047836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0;
23057836SJohn.Forte@Sun.COM 		}
23067836SJohn.Forte@Sun.COM 
23077836SJohn.Forte@Sun.COM 		if (ilu->ilu_next)
23087836SJohn.Forte@Sun.COM 			ilu->ilu_next->ilu_prev = ilu->ilu_prev;
23097836SJohn.Forte@Sun.COM 		if (ilu->ilu_prev)
23107836SJohn.Forte@Sun.COM 			ilu->ilu_prev->ilu_next = ilu->ilu_next;
23117836SJohn.Forte@Sun.COM 		else
23127836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilulist = ilu->ilu_next;
23137836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlus--;
23147836SJohn.Forte@Sun.COM 
23157836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_draining) {
23167836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
23177836SJohn.Forte@Sun.COM 		}
23187836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_timing) {
23197836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
23207836SJohn.Forte@Sun.COM 		}
23217836SJohn.Forte@Sun.COM 		if (lu->lu_lp) {
23227836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
23237836SJohn.Forte@Sun.COM 			    (lu->lu_lp->lp_stmf_private))->ilp_nlus--;
23247836SJohn.Forte@Sun.COM 		}
23257836SJohn.Forte@Sun.COM 		if (ilu->ilu_luid) {
23267836SJohn.Forte@Sun.COM 			((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object =
23277836SJohn.Forte@Sun.COM 			    NULL;
23287836SJohn.Forte@Sun.COM 			ilu->ilu_luid = NULL;
23297836SJohn.Forte@Sun.COM 		}
23307836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl);
23317836SJohn.Forte@Sun.COM 	} else {
23327836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
23337836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
23347836SJohn.Forte@Sun.COM 	}
23359435STim.Szeto@Sun.COM 	if (ilu->ilu_kstat_info) {
23369435STim.Szeto@Sun.COM 		kstat_delete(ilu->ilu_kstat_info);
23379435STim.Szeto@Sun.COM 	}
23389435STim.Szeto@Sun.COM 	if (ilu->ilu_kstat_io) {
23399435STim.Szeto@Sun.COM 		kstat_delete(ilu->ilu_kstat_io);
23409435STim.Szeto@Sun.COM 		mutex_destroy(&ilu->ilu_kstat_lock);
23419435STim.Szeto@Sun.COM 	}
23427836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
23437836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
23447836SJohn.Forte@Sun.COM }
23457836SJohn.Forte@Sun.COM 
23467836SJohn.Forte@Sun.COM stmf_status_t
23477836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport)
23487836SJohn.Forte@Sun.COM {
23497836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
23507836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
23517836SJohn.Forte@Sun.COM 	int start_workers = 0;
23527836SJohn.Forte@Sun.COM 
23537836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
23547836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
23557836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
23567836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
23577836SJohn.Forte@Sun.COM 	}
23587836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
23597836SJohn.Forte@Sun.COM 	rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL);
23607836SJohn.Forte@Sun.COM 
23617836SJohn.Forte@Sun.COM 	ilport->ilport_next = stmf_state.stmf_ilportlist;
23627836SJohn.Forte@Sun.COM 	ilport->ilport_prev = NULL;
23637836SJohn.Forte@Sun.COM 	if (ilport->ilport_next)
23647836SJohn.Forte@Sun.COM 		ilport->ilport_next->ilport_prev = ilport;
23657836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilportlist = ilport;
23667836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlports++;
23677836SJohn.Forte@Sun.COM 	if (lport->lport_pp) {
23687836SJohn.Forte@Sun.COM 		((stmf_i_port_provider_t *)
23697836SJohn.Forte@Sun.COM 		    (lport->lport_pp->pp_stmf_private))->ipp_npps++;
23707836SJohn.Forte@Sun.COM 	}
23717836SJohn.Forte@Sun.COM 	ilport->ilport_tg =
23727836SJohn.Forte@Sun.COM 	    stmf_lookup_group_for_target(lport->lport_id->ident,
23738662SJordan.Vaughan@Sun.com 	    lport->lport_id->ident_length);
23747836SJohn.Forte@Sun.COM 	ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1);
23757836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl);
23769435STim.Szeto@Sun.COM 	stmf_create_kstat_lport(ilport);
23777836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED) {
23787836SJohn.Forte@Sun.COM 		stmf_workers_state = STMF_WORKERS_ENABLING;
23797836SJohn.Forte@Sun.COM 		start_workers = 1;
23807836SJohn.Forte@Sun.COM 	}
23817836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
23827836SJohn.Forte@Sun.COM 
23837836SJohn.Forte@Sun.COM 	if (start_workers)
23847836SJohn.Forte@Sun.COM 		stmf_worker_init();
23857836SJohn.Forte@Sun.COM 
23867836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lport can be brought online */
23877836SJohn.Forte@Sun.COM 	ilport->ilport_prev_state = STMF_STATE_ONLINE;
23887836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
23897836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
23907836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
23917836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci);
23927836SJohn.Forte@Sun.COM 	}
23937836SJohn.Forte@Sun.COM 
23947836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
23957836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
23967836SJohn.Forte@Sun.COM }
23977836SJohn.Forte@Sun.COM 
23987836SJohn.Forte@Sun.COM stmf_status_t
23997836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport)
24007836SJohn.Forte@Sun.COM {
24017836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
24027836SJohn.Forte@Sun.COM 
24037836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
24047836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
24057836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
24067836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
24077836SJohn.Forte@Sun.COM 	}
24087836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
24097836SJohn.Forte@Sun.COM 	if (ilport->ilport_nsessions == 0) {
24107836SJohn.Forte@Sun.COM 		if (ilport->ilport_next)
24117836SJohn.Forte@Sun.COM 			ilport->ilport_next->ilport_prev = ilport->ilport_prev;
24127836SJohn.Forte@Sun.COM 		if (ilport->ilport_prev)
24137836SJohn.Forte@Sun.COM 			ilport->ilport_prev->ilport_next = ilport->ilport_next;
24147836SJohn.Forte@Sun.COM 		else
24157836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilportlist = ilport->ilport_next;
24167836SJohn.Forte@Sun.COM 		rw_destroy(&ilport->ilport_lock);
24177836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlports--;
24187836SJohn.Forte@Sun.COM 		if (lport->lport_pp) {
24197836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
24207836SJohn.Forte@Sun.COM 			    (lport->lport_pp->pp_stmf_private))->ipp_npps--;
24217836SJohn.Forte@Sun.COM 		}
24227836SJohn.Forte@Sun.COM 		ilport->ilport_tg = NULL;
24237836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl);
24247836SJohn.Forte@Sun.COM 	} else {
24257836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
24267836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
24277836SJohn.Forte@Sun.COM 	}
24289435STim.Szeto@Sun.COM 	if (ilport->ilport_kstat_info) {
24299435STim.Szeto@Sun.COM 		kstat_delete(ilport->ilport_kstat_info);
24309435STim.Szeto@Sun.COM 	}
24319435STim.Szeto@Sun.COM 	if (ilport->ilport_kstat_io) {
24329435STim.Szeto@Sun.COM 		kstat_delete(ilport->ilport_kstat_io);
24339435STim.Szeto@Sun.COM 		mutex_destroy(&ilport->ilport_kstat_lock);
24349435STim.Szeto@Sun.COM 	}
24357836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
24367836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
24377836SJohn.Forte@Sun.COM }
24387836SJohn.Forte@Sun.COM 
24397836SJohn.Forte@Sun.COM /*
24407836SJohn.Forte@Sun.COM  * Port provider has to make sure that register/deregister session and
24417836SJohn.Forte@Sun.COM  * port are serialized calls.
24427836SJohn.Forte@Sun.COM  */
24437836SJohn.Forte@Sun.COM stmf_status_t
24447836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
24457836SJohn.Forte@Sun.COM {
24467836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
24477836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
24487836SJohn.Forte@Sun.COM 	    lport->lport_stmf_private;
24497836SJohn.Forte@Sun.COM 	uint8_t		lun[8];
24507836SJohn.Forte@Sun.COM 
24517836SJohn.Forte@Sun.COM 	/*
24527836SJohn.Forte@Sun.COM 	 * Port state has to be online to register a scsi session. It is
24537836SJohn.Forte@Sun.COM 	 * possible that we started an offline operation and a new SCSI
24547836SJohn.Forte@Sun.COM 	 * session started at the same time (in that case also we are going
24557836SJohn.Forte@Sun.COM 	 * to fail the registeration). But any other state is simply
24567836SJohn.Forte@Sun.COM 	 * a bad port provider implementation.
24577836SJohn.Forte@Sun.COM 	 */
24587836SJohn.Forte@Sun.COM 	if (ilport->ilport_state != STMF_STATE_ONLINE) {
24597836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
24607836SJohn.Forte@Sun.COM 			stmf_trace(lport->lport_alias, "Port is trying to "
24617836SJohn.Forte@Sun.COM 			    "register a session while the state is neither "
24627836SJohn.Forte@Sun.COM 			    "online nor offlining");
24637836SJohn.Forte@Sun.COM 		}
24647836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
24657836SJohn.Forte@Sun.COM 	}
24667836SJohn.Forte@Sun.COM 	bzero(lun, 8);
24677836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
24687836SJohn.Forte@Sun.COM 	iss->iss_flags |= ISS_BEING_CREATED;
24697836SJohn.Forte@Sun.COM 
24707836SJohn.Forte@Sun.COM 	/* sessions use the ilport_lock. No separate lock is required */
24717836SJohn.Forte@Sun.COM 	iss->iss_lockp = &ilport->ilport_lock;
24727836SJohn.Forte@Sun.COM 	(void) stmf_session_create_lun_map(ilport, iss);
24737836SJohn.Forte@Sun.COM 
24747836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
24757836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions++;
24767836SJohn.Forte@Sun.COM 	iss->iss_next = ilport->ilport_ss_list;
24777836SJohn.Forte@Sun.COM 	ilport->ilport_ss_list = iss;
24787836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
24797836SJohn.Forte@Sun.COM 
24807836SJohn.Forte@Sun.COM 	iss->iss_creation_time = ddi_get_time();
24817836SJohn.Forte@Sun.COM 	ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1);
24827836SJohn.Forte@Sun.COM 	iss->iss_flags &= ~ISS_BEING_CREATED;
24838859STim.Szeto@Sun.COM 	DTRACE_PROBE2(session__online, stmf_local_port_t *, lport,
24848859STim.Szeto@Sun.COM 	    stmf_scsi_session_t *, ss);
24857836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
24867836SJohn.Forte@Sun.COM }
24877836SJohn.Forte@Sun.COM 
24887836SJohn.Forte@Sun.COM void
24897836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
24907836SJohn.Forte@Sun.COM {
24917836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
24928662SJordan.Vaughan@Sun.com 	    lport->lport_stmf_private;
24937836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss, **ppss;
24947836SJohn.Forte@Sun.COM 	int found = 0;
24957836SJohn.Forte@Sun.COM 
24968859STim.Szeto@Sun.COM 	DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport,
24978859STim.Szeto@Sun.COM 	    stmf_scsi_session_t *, ss);
24988859STim.Szeto@Sun.COM 
24997836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
25007836SJohn.Forte@Sun.COM 	if (ss->ss_rport_alias) {
25017836SJohn.Forte@Sun.COM 		ss->ss_rport_alias = NULL;
25027836SJohn.Forte@Sun.COM 	}
25037836SJohn.Forte@Sun.COM 
25047836SJohn.Forte@Sun.COM try_dereg_ss_again:
25057836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
25067836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
25078662SJordan.Vaughan@Sun.com 	    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
25087836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_EVENT_ACTIVE) {
25097836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
25107836SJohn.Forte@Sun.COM 		delay(1);
25117836SJohn.Forte@Sun.COM 		goto try_dereg_ss_again;
25127836SJohn.Forte@Sun.COM 	}
25137836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
25147836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
25157836SJohn.Forte@Sun.COM 	for (ppss = &ilport->ilport_ss_list; *ppss != NULL;
25167836SJohn.Forte@Sun.COM 	    ppss = &((*ppss)->iss_next)) {
25177836SJohn.Forte@Sun.COM 		if (iss == (*ppss)) {
25187836SJohn.Forte@Sun.COM 			*ppss = (*ppss)->iss_next;
25197836SJohn.Forte@Sun.COM 			found = 1;
25207836SJohn.Forte@Sun.COM 			break;
25217836SJohn.Forte@Sun.COM 		}
25227836SJohn.Forte@Sun.COM 	}
25237836SJohn.Forte@Sun.COM 	if (!found) {
25247836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "Deregister session called for non existent"
25257836SJohn.Forte@Sun.COM 		    " session");
25267836SJohn.Forte@Sun.COM 	}
25277836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions--;
25287836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
25297836SJohn.Forte@Sun.COM 
25307836SJohn.Forte@Sun.COM 	(void) stmf_session_destroy_lun_map(ilport, iss);
25317836SJohn.Forte@Sun.COM }
25327836SJohn.Forte@Sun.COM 
25337836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *
25347836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked)
25357836SJohn.Forte@Sun.COM {
25367836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
25377836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
25387836SJohn.Forte@Sun.COM 
25397836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
25407836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
25418662SJordan.Vaughan@Sun.com 	    ilport = ilport->ilport_next) {
25427836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
25437836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
25448662SJordan.Vaughan@Sun.com 		    iss = iss->iss_next) {
25457836SJohn.Forte@Sun.COM 			if (iss->iss_ss->ss_session_id == session_id) {
25467836SJohn.Forte@Sun.COM 				if (!stay_locked)
25477836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
25487836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
25497836SJohn.Forte@Sun.COM 				return (iss);
25507836SJohn.Forte@Sun.COM 			}
25517836SJohn.Forte@Sun.COM 		}
25527836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
25537836SJohn.Forte@Sun.COM 	}
25547836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
25557836SJohn.Forte@Sun.COM 	return (NULL);
25567836SJohn.Forte@Sun.COM }
25577836SJohn.Forte@Sun.COM 
25587836SJohn.Forte@Sun.COM void
25597836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
25607836SJohn.Forte@Sun.COM {
25617836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itlpp;
25627836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
25637836SJohn.Forte@Sun.COM 
25647836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED);
25657836SJohn.Forte@Sun.COM 
25667836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
25677836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
25687836SJohn.Forte@Sun.COM 	for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL;
25698662SJordan.Vaughan@Sun.com 	    itlpp = &(*itlpp)->itl_next) {
25707836SJohn.Forte@Sun.COM 		if ((*itlpp) == itl)
25717836SJohn.Forte@Sun.COM 			break;
25727836SJohn.Forte@Sun.COM 	}
25737836SJohn.Forte@Sun.COM 	ASSERT((*itlpp) != NULL);
25747836SJohn.Forte@Sun.COM 	*itlpp = itl->itl_next;
25757836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
25767836SJohn.Forte@Sun.COM 	lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle,
25778662SJordan.Vaughan@Sun.com 	    (uint32_t)itl->itl_hdlrm_reason);
25787836SJohn.Forte@Sun.COM 	kmem_free(itl, sizeof (*itl));
25797836SJohn.Forte@Sun.COM }
25807836SJohn.Forte@Sun.COM 
25817836SJohn.Forte@Sun.COM stmf_status_t
25827836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun,
25837836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
25847836SJohn.Forte@Sun.COM {
25857836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
25867836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
25877836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
25887836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
25897836SJohn.Forte@Sun.COM 	uint16_t n;
25907836SJohn.Forte@Sun.COM 
25917836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
25927836SJohn.Forte@Sun.COM 	if (ss == NULL) {
25937836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
25947836SJohn.Forte@Sun.COM 		if (iss == NULL)
25957836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
25967836SJohn.Forte@Sun.COM 	} else {
25977836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
25987836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
25997836SJohn.Forte@Sun.COM 	}
26007836SJohn.Forte@Sun.COM 
26017836SJohn.Forte@Sun.COM 	n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
26027836SJohn.Forte@Sun.COM 	lun_map_ent = (stmf_lun_map_ent_t *)
26038662SJordan.Vaughan@Sun.com 	    stmf_get_ent_from_map(iss->iss_sm, n);
26047836SJohn.Forte@Sun.COM 	if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) {
26057836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26067836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
26077836SJohn.Forte@Sun.COM 	}
26087836SJohn.Forte@Sun.COM 	if (lun_map_ent->ent_itl_datap != NULL) {
26097836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26107836SJohn.Forte@Sun.COM 		return (STMF_ALREADY);
26117836SJohn.Forte@Sun.COM 	}
26127836SJohn.Forte@Sun.COM 
26137836SJohn.Forte@Sun.COM 	itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP);
26147836SJohn.Forte@Sun.COM 	if (itl == NULL) {
26157836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26167836SJohn.Forte@Sun.COM 		return (STMF_ALLOC_FAILURE);
26177836SJohn.Forte@Sun.COM 	}
26187836SJohn.Forte@Sun.COM 
26197836SJohn.Forte@Sun.COM 	itl->itl_counter = 1;
26207836SJohn.Forte@Sun.COM 	itl->itl_lun = n;
26217836SJohn.Forte@Sun.COM 	itl->itl_handle = itl_handle;
26227836SJohn.Forte@Sun.COM 	itl->itl_session = iss;
26237836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
26247836SJohn.Forte@Sun.COM 	itl->itl_next = ilu->ilu_itl_list;
26257836SJohn.Forte@Sun.COM 	ilu->ilu_itl_list = itl;
26267836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
26277836SJohn.Forte@Sun.COM 	lun_map_ent->ent_itl_datap = itl;
26287836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
26297836SJohn.Forte@Sun.COM 
26307836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
26317836SJohn.Forte@Sun.COM }
26327836SJohn.Forte@Sun.COM 
26337836SJohn.Forte@Sun.COM void
26347836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason)
26357836SJohn.Forte@Sun.COM {
26367836SJohn.Forte@Sun.COM 	uint8_t old, new;
26377836SJohn.Forte@Sun.COM 
26387836SJohn.Forte@Sun.COM 	do {
26397836SJohn.Forte@Sun.COM 		old = new = itl->itl_flags;
26407836SJohn.Forte@Sun.COM 		if (old & STMF_ITL_BEING_TERMINATED)
26417836SJohn.Forte@Sun.COM 			return;
26427836SJohn.Forte@Sun.COM 		new |= STMF_ITL_BEING_TERMINATED;
26437836SJohn.Forte@Sun.COM 	} while (atomic_cas_8(&itl->itl_flags, old, new) != old);
26447836SJohn.Forte@Sun.COM 	itl->itl_hdlrm_reason = hdlrm_reason;
26457836SJohn.Forte@Sun.COM 
26467836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_counter);
26477836SJohn.Forte@Sun.COM 
26487836SJohn.Forte@Sun.COM 	if (atomic_add_32_nv(&itl->itl_counter, -1))
26497836SJohn.Forte@Sun.COM 		return;
26507836SJohn.Forte@Sun.COM 
26517836SJohn.Forte@Sun.COM 	drv_usecwait(10);
26527836SJohn.Forte@Sun.COM 	if (itl->itl_counter)
26537836SJohn.Forte@Sun.COM 		return;
26547836SJohn.Forte@Sun.COM 
26557836SJohn.Forte@Sun.COM 	stmf_release_itl_handle(lu, itl);
26567836SJohn.Forte@Sun.COM }
26577836SJohn.Forte@Sun.COM 
26587836SJohn.Forte@Sun.COM stmf_status_t
26597836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu)
26607836SJohn.Forte@Sun.COM {
26617836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
26627836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
26637836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
26647836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
26657836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
26667836SJohn.Forte@Sun.COM 	uint32_t nmaps, nu;
26677836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itl_list;
26687836SJohn.Forte@Sun.COM 	int i;
26697836SJohn.Forte@Sun.COM 
26707836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
26717836SJohn.Forte@Sun.COM 
26727836SJohn.Forte@Sun.COM dereg_itl_start:;
26737836SJohn.Forte@Sun.COM 	nmaps = ilu->ilu_ref_cnt;
26747836SJohn.Forte@Sun.COM 	if (nmaps == 0)
26757836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
26767836SJohn.Forte@Sun.COM 	itl_list = (stmf_itl_data_t **)kmem_zalloc(
26778662SJordan.Vaughan@Sun.com 	    nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP);
26787836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
26797836SJohn.Forte@Sun.COM 	if (nmaps != ilu->ilu_ref_cnt) {
26807836SJohn.Forte@Sun.COM 		/* Something changed, start all over */
26817836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
26827836SJohn.Forte@Sun.COM 		kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
26837836SJohn.Forte@Sun.COM 		goto dereg_itl_start;
26847836SJohn.Forte@Sun.COM 	}
26857836SJohn.Forte@Sun.COM 	nu = 0;
26867836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
26878662SJordan.Vaughan@Sun.com 	    ilport = ilport->ilport_next) {
26887836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
26897836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
26908662SJordan.Vaughan@Sun.com 		    iss = iss->iss_next) {
26917836SJohn.Forte@Sun.COM 			lm = iss->iss_sm;
26927836SJohn.Forte@Sun.COM 			if (!lm)
26937836SJohn.Forte@Sun.COM 				continue;
26947836SJohn.Forte@Sun.COM 			for (i = 0; i < lm->lm_nentries; i++) {
26957836SJohn.Forte@Sun.COM 				if (lm->lm_plus[i] == NULL)
26967836SJohn.Forte@Sun.COM 					continue;
26977836SJohn.Forte@Sun.COM 				ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
26987836SJohn.Forte@Sun.COM 				if ((ent->ent_lu == lu) &&
26998662SJordan.Vaughan@Sun.com 				    (ent->ent_itl_datap)) {
27007836SJohn.Forte@Sun.COM 					itl_list[nu++] = ent->ent_itl_datap;
27017836SJohn.Forte@Sun.COM 					ent->ent_itl_datap = NULL;
27027836SJohn.Forte@Sun.COM 					if (nu == nmaps) {
27037836SJohn.Forte@Sun.COM 						rw_exit(&ilport->ilport_lock);
27047836SJohn.Forte@Sun.COM 						goto dai_scan_done;
27057836SJohn.Forte@Sun.COM 					}
27067836SJohn.Forte@Sun.COM 				}
27077836SJohn.Forte@Sun.COM 			} /* lun table for a session */
27087836SJohn.Forte@Sun.COM 		} /* sessions */
27097836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
27107836SJohn.Forte@Sun.COM 	} /* ports */
27117836SJohn.Forte@Sun.COM 
27127836SJohn.Forte@Sun.COM dai_scan_done:
27137836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
27147836SJohn.Forte@Sun.COM 
27157836SJohn.Forte@Sun.COM 	for (i = 0; i < nu; i++) {
27167836SJohn.Forte@Sun.COM 		stmf_do_itl_dereg(lu, itl_list[i],
27178662SJordan.Vaughan@Sun.com 		    STMF_ITL_REASON_DEREG_REQUEST);
27187836SJohn.Forte@Sun.COM 	}
27197836SJohn.Forte@Sun.COM 	kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
27207836SJohn.Forte@Sun.COM 
27217836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
27227836SJohn.Forte@Sun.COM }
27237836SJohn.Forte@Sun.COM 
27247836SJohn.Forte@Sun.COM stmf_status_t
27257836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
27267836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
27277836SJohn.Forte@Sun.COM {
27287836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
27297836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
27307836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
27317836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
27327836SJohn.Forte@Sun.COM 	int i;
27337836SJohn.Forte@Sun.COM 	uint16_t n;
27347836SJohn.Forte@Sun.COM 
27357836SJohn.Forte@Sun.COM 	if (ss == NULL) {
27367836SJohn.Forte@Sun.COM 		if (session_id == STMF_SESSION_ID_NONE)
27377836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
27387836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
27397836SJohn.Forte@Sun.COM 		if (iss == NULL)
27407836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
27417836SJohn.Forte@Sun.COM 	} else {
27427836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
27437836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
27447836SJohn.Forte@Sun.COM 	}
27457836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
27467836SJohn.Forte@Sun.COM 	if (lm == NULL) {
27477836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
27487836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
27497836SJohn.Forte@Sun.COM 	}
27507836SJohn.Forte@Sun.COM 
27517836SJohn.Forte@Sun.COM 	if (lun) {
27527836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
27537836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
27548662SJordan.Vaughan@Sun.com 		    stmf_get_ent_from_map(iss->iss_sm, n);
27557836SJohn.Forte@Sun.COM 	} else {
27567836SJohn.Forte@Sun.COM 		if (itl_handle == NULL) {
27577836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
27587836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
27597836SJohn.Forte@Sun.COM 		}
27607836SJohn.Forte@Sun.COM 		ent = NULL;
27617836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
27627836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
27637836SJohn.Forte@Sun.COM 				continue;
27647836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
27657836SJohn.Forte@Sun.COM 			if (ent->ent_itl_datap &&
27667836SJohn.Forte@Sun.COM 			    (ent->ent_itl_datap->itl_handle == itl_handle)) {
27677836SJohn.Forte@Sun.COM 				break;
27687836SJohn.Forte@Sun.COM 			}
27697836SJohn.Forte@Sun.COM 		}
27707836SJohn.Forte@Sun.COM 	}
27717836SJohn.Forte@Sun.COM 	if ((ent == NULL) || (ent->ent_lu != lu) ||
27728662SJordan.Vaughan@Sun.com 	    (ent->ent_itl_datap == NULL)) {
27737836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
27747836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
27757836SJohn.Forte@Sun.COM 	}
27767836SJohn.Forte@Sun.COM 	itl = ent->ent_itl_datap;
27777836SJohn.Forte@Sun.COM 	ent->ent_itl_datap = NULL;
27787836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
27797836SJohn.Forte@Sun.COM 	stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
27807836SJohn.Forte@Sun.COM 
27817836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
27827836SJohn.Forte@Sun.COM }
27837836SJohn.Forte@Sun.COM 
27847836SJohn.Forte@Sun.COM stmf_status_t
27857836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
27867836SJohn.Forte@Sun.COM     uint64_t session_id, void **itl_handle_retp)
27877836SJohn.Forte@Sun.COM {
27887836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
27897836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
27907836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
27917836SJohn.Forte@Sun.COM 	stmf_status_t ret;
27927836SJohn.Forte@Sun.COM 	int i;
27937836SJohn.Forte@Sun.COM 	uint16_t n;
27947836SJohn.Forte@Sun.COM 
27957836SJohn.Forte@Sun.COM 	if (ss == NULL) {
27967836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
27977836SJohn.Forte@Sun.COM 		if (iss == NULL)
27987836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
27997836SJohn.Forte@Sun.COM 	} else {
28007836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
28017836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
28027836SJohn.Forte@Sun.COM 	}
28037836SJohn.Forte@Sun.COM 
28047836SJohn.Forte@Sun.COM 	ent = NULL;
28057836SJohn.Forte@Sun.COM 	if (lun == NULL) {
28067836SJohn.Forte@Sun.COM 		lm = iss->iss_sm;
28077836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
28087836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
28097836SJohn.Forte@Sun.COM 				continue;
28107836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
28117836SJohn.Forte@Sun.COM 			if (ent->ent_lu == lu)
28127836SJohn.Forte@Sun.COM 				break;
28137836SJohn.Forte@Sun.COM 		}
28147836SJohn.Forte@Sun.COM 	} else {
28157836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
28167836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
28178662SJordan.Vaughan@Sun.com 		    stmf_get_ent_from_map(iss->iss_sm, n);
28187836SJohn.Forte@Sun.COM 		if (lu && (ent->ent_lu != lu))
28197836SJohn.Forte@Sun.COM 			ent = NULL;
28207836SJohn.Forte@Sun.COM 	}
28217836SJohn.Forte@Sun.COM 	if (ent && ent->ent_itl_datap) {
28227836SJohn.Forte@Sun.COM 		*itl_handle_retp = ent->ent_itl_datap->itl_handle;
28237836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
28247836SJohn.Forte@Sun.COM 	} else {
28257836SJohn.Forte@Sun.COM 		ret = STMF_NOT_FOUND;
28267836SJohn.Forte@Sun.COM 	}
28277836SJohn.Forte@Sun.COM 
28287836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
28297836SJohn.Forte@Sun.COM 	return (ret);
28307836SJohn.Forte@Sun.COM }
28317836SJohn.Forte@Sun.COM 
28327836SJohn.Forte@Sun.COM stmf_data_buf_t *
28337836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
28347836SJohn.Forte@Sun.COM     uint32_t flags)
28357836SJohn.Forte@Sun.COM {
28367836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
28377836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
28387836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
28397836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
28407836SJohn.Forte@Sun.COM 	uint8_t ndx;
28417836SJohn.Forte@Sun.COM 
28427836SJohn.Forte@Sun.COM 	ndx = stmf_first_zero[itask->itask_allocated_buf_map];
28437836SJohn.Forte@Sun.COM 	if (ndx == 0xff)
28447836SJohn.Forte@Sun.COM 		return (NULL);
28457836SJohn.Forte@Sun.COM 	dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf(
28467836SJohn.Forte@Sun.COM 	    task, size, pminsize, flags);
28477836SJohn.Forte@Sun.COM 	if (dbuf) {
28487836SJohn.Forte@Sun.COM 		task->task_cur_nbufs++;
28497836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map |= (1 << ndx);
28507836SJohn.Forte@Sun.COM 		dbuf->db_handle = ndx;
28517836SJohn.Forte@Sun.COM 		return (dbuf);
28527836SJohn.Forte@Sun.COM 	}
28537836SJohn.Forte@Sun.COM 
28547836SJohn.Forte@Sun.COM 	return (NULL);
28557836SJohn.Forte@Sun.COM }
28567836SJohn.Forte@Sun.COM 
28577836SJohn.Forte@Sun.COM void
28587836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf)
28597836SJohn.Forte@Sun.COM {
28607836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
28617836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
28627836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
28637836SJohn.Forte@Sun.COM 
28647836SJohn.Forte@Sun.COM 	itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle);
28657836SJohn.Forte@Sun.COM 	task->task_cur_nbufs--;
28667836SJohn.Forte@Sun.COM 	lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf);
28677836SJohn.Forte@Sun.COM }
28687836SJohn.Forte@Sun.COM 
28697836SJohn.Forte@Sun.COM stmf_data_buf_t *
28707836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h)
28717836SJohn.Forte@Sun.COM {
28727836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
28737836SJohn.Forte@Sun.COM 
28747836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
28757836SJohn.Forte@Sun.COM 	if (h > 3)
28767836SJohn.Forte@Sun.COM 		return (NULL);
28777836SJohn.Forte@Sun.COM 	return (itask->itask_dbufs[h]);
28787836SJohn.Forte@Sun.COM }
28797836SJohn.Forte@Sun.COM 
28807836SJohn.Forte@Sun.COM /* ARGSUSED */
28817836SJohn.Forte@Sun.COM struct scsi_task *
28827836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss,
28837836SJohn.Forte@Sun.COM 			uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id)
28847836SJohn.Forte@Sun.COM {
28857836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
28867836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
28877836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
28887836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
28897836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t **ppitask;
28907836SJohn.Forte@Sun.COM 	scsi_task_t *task;
28917836SJohn.Forte@Sun.COM 	uint64_t *p;
28927836SJohn.Forte@Sun.COM 	uint8_t	*l;
28937836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
28947836SJohn.Forte@Sun.COM 	uint16_t cdb_length;
28957836SJohn.Forte@Sun.COM 	uint16_t luNbr;
28967836SJohn.Forte@Sun.COM 	uint8_t new_task = 0;
28977836SJohn.Forte@Sun.COM 
28987836SJohn.Forte@Sun.COM 	/*
28997836SJohn.Forte@Sun.COM 	 * We allocate 7 extra bytes for CDB to provide a cdb pointer which
29007836SJohn.Forte@Sun.COM 	 * is guaranteed to be 8 byte aligned. Some LU providers like OSD
29017836SJohn.Forte@Sun.COM 	 * depend upon this alignment.
29027836SJohn.Forte@Sun.COM 	 */
29037836SJohn.Forte@Sun.COM 	if (cdb_length_in >= 16)
29047836SJohn.Forte@Sun.COM 		cdb_length = cdb_length_in + 7;
29057836SJohn.Forte@Sun.COM 	else
29067836SJohn.Forte@Sun.COM 		cdb_length = 16 + 7;
29077836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
29087836SJohn.Forte@Sun.COM 	luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
29097836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
29107836SJohn.Forte@Sun.COM 	lun_map_ent =
29117836SJohn.Forte@Sun.COM 	    (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr);
29127836SJohn.Forte@Sun.COM 	if (!lun_map_ent) {
29137836SJohn.Forte@Sun.COM 		lu = dlun0;
29147836SJohn.Forte@Sun.COM 	} else {
29157836SJohn.Forte@Sun.COM 		lu = lun_map_ent->ent_lu;
29167836SJohn.Forte@Sun.COM 	}
29177836SJohn.Forte@Sun.COM 	ilu = lu->lu_stmf_private;
29187836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
29197836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
29207836SJohn.Forte@Sun.COM 		return (NULL);
29217836SJohn.Forte@Sun.COM 	}
29227836SJohn.Forte@Sun.COM 	do {
29237836SJohn.Forte@Sun.COM 		if (ilu->ilu_free_tasks == NULL) {
29247836SJohn.Forte@Sun.COM 			new_task = 1;
29257836SJohn.Forte@Sun.COM 			break;
29267836SJohn.Forte@Sun.COM 		}
29277836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
29287836SJohn.Forte@Sun.COM 		for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) &&
29297836SJohn.Forte@Sun.COM 		    ((*ppitask)->itask_cdb_buf_size < cdb_length);
29308662SJordan.Vaughan@Sun.com 		    ppitask = &((*ppitask)->itask_lu_free_next))
29318662SJordan.Vaughan@Sun.com 			;
29327836SJohn.Forte@Sun.COM 		if (*ppitask) {
29337836SJohn.Forte@Sun.COM 			itask = *ppitask;
29347836SJohn.Forte@Sun.COM 			*ppitask = (*ppitask)->itask_lu_free_next;
29357836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_free--;
29367836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free)
29377836SJohn.Forte@Sun.COM 				ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
29387836SJohn.Forte@Sun.COM 		} else {
29397836SJohn.Forte@Sun.COM 			new_task = 1;
29407836SJohn.Forte@Sun.COM 		}
29417836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
29427836SJohn.Forte@Sun.COM 	/* CONSTCOND */
29437836SJohn.Forte@Sun.COM 	} while (0);
29447836SJohn.Forte@Sun.COM 
29457836SJohn.Forte@Sun.COM 	if (!new_task) {
29467836SJohn.Forte@Sun.COM 		task = itask->itask_task;
29477836SJohn.Forte@Sun.COM 		task->task_timeout = 0;
29487836SJohn.Forte@Sun.COM 		p = (uint64_t *)&task->task_flags;
29497836SJohn.Forte@Sun.COM 		*p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0;
29507836SJohn.Forte@Sun.COM 		itask->itask_ncmds = 0;
29517836SJohn.Forte@Sun.COM 	} else {
29527836SJohn.Forte@Sun.COM 		task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK,
29537836SJohn.Forte@Sun.COM 		    cdb_length, AF_FORCE_NOSLEEP);
29547836SJohn.Forte@Sun.COM 		if (task == NULL) {
29557836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
29567836SJohn.Forte@Sun.COM 			return (NULL);
29577836SJohn.Forte@Sun.COM 		}
29587836SJohn.Forte@Sun.COM 		task->task_lu = lu;
29597836SJohn.Forte@Sun.COM 		l = task->task_lun_no;
29607836SJohn.Forte@Sun.COM 		l[0] = lun[0];
29617836SJohn.Forte@Sun.COM 		l[1] = lun[1];
29627836SJohn.Forte@Sun.COM 		l[2] = lun[2];
29637836SJohn.Forte@Sun.COM 		l[3] = lun[3];
29647836SJohn.Forte@Sun.COM 		l[4] = lun[4];
29657836SJohn.Forte@Sun.COM 		l[5] = lun[5];
29667836SJohn.Forte@Sun.COM 		l[6] = lun[6];
29677836SJohn.Forte@Sun.COM 		l[7] = lun[7];
29687836SJohn.Forte@Sun.COM 		task->task_cdb = (uint8_t *)task->task_port_private;
29697836SJohn.Forte@Sun.COM 		if ((ulong_t)(task->task_cdb) & 7ul) {
29707836SJohn.Forte@Sun.COM 			task->task_cdb = (uint8_t *)(((ulong_t)
29717836SJohn.Forte@Sun.COM 			    (task->task_cdb) + 7ul) & ~(7ul));
29727836SJohn.Forte@Sun.COM 		}
29737836SJohn.Forte@Sun.COM 		itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
29747836SJohn.Forte@Sun.COM 		itask->itask_cdb_buf_size = cdb_length;
29757836SJohn.Forte@Sun.COM 	}
29767836SJohn.Forte@Sun.COM 	task->task_session = ss;
29777836SJohn.Forte@Sun.COM 	task->task_lport = lport;
29787836SJohn.Forte@Sun.COM 	task->task_cdb_length = cdb_length_in;
29797836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_TRANSITION;
29807836SJohn.Forte@Sun.COM 
29817836SJohn.Forte@Sun.COM 	if (new_task) {
29827836SJohn.Forte@Sun.COM 		if (lu->lu_task_alloc(task) != STMF_SUCCESS) {
29837836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
29847836SJohn.Forte@Sun.COM 			stmf_free(task);
29857836SJohn.Forte@Sun.COM 			return (NULL);
29867836SJohn.Forte@Sun.COM 		}
29877836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
29887836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
29897836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
29907836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
29917836SJohn.Forte@Sun.COM 			stmf_free(task);
29927836SJohn.Forte@Sun.COM 			return (NULL);
29937836SJohn.Forte@Sun.COM 		}
29947836SJohn.Forte@Sun.COM 		itask->itask_lu_next = ilu->ilu_tasks;
29957836SJohn.Forte@Sun.COM 		if (ilu->ilu_tasks)
29967836SJohn.Forte@Sun.COM 			ilu->ilu_tasks->itask_lu_prev = itask;
29977836SJohn.Forte@Sun.COM 		ilu->ilu_tasks = itask;
29987836SJohn.Forte@Sun.COM 		/* kmem_zalloc automatically makes itask->itask_lu_prev NULL */
29997836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks++;
30007836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30017836SJohn.Forte@Sun.COM 	}
30027836SJohn.Forte@Sun.COM 
30037836SJohn.Forte@Sun.COM 	itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr;
30047836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, 1);
30057836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
30067836SJohn.Forte@Sun.COM 
30077836SJohn.Forte@Sun.COM 	if ((lun_map_ent != NULL) && ((itask->itask_itl_datap =
30087836SJohn.Forte@Sun.COM 	    lun_map_ent->ent_itl_datap) != NULL)) {
30097836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_itl_datap->itl_counter, 1);
30107836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle;
30117836SJohn.Forte@Sun.COM 	} else {
30127836SJohn.Forte@Sun.COM 		itask->itask_itl_datap = NULL;
30137836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = NULL;
30147836SJohn.Forte@Sun.COM 	}
30157836SJohn.Forte@Sun.COM 
30167836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
30177836SJohn.Forte@Sun.COM 	return (task);
30187836SJohn.Forte@Sun.COM }
30197836SJohn.Forte@Sun.COM 
30207836SJohn.Forte@Sun.COM void
30217836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task)
30227836SJohn.Forte@Sun.COM {
30237836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
30247836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
30257836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
30267836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
30277836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
30287836SJohn.Forte@Sun.COM 
30297836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
30307836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_FREE_LIST;
30317836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
30327836SJohn.Forte@Sun.COM 	itask->itask_lu_free_next = ilu->ilu_free_tasks;
30337836SJohn.Forte@Sun.COM 	ilu->ilu_free_tasks = itask;
30347836SJohn.Forte@Sun.COM 	ilu->ilu_ntasks_free++;
30357836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
30367836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, -1);
30377836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
30387836SJohn.Forte@Sun.COM }
30397836SJohn.Forte@Sun.COM 
30407836SJohn.Forte@Sun.COM void
30417836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu)
30427836SJohn.Forte@Sun.COM {
30437836SJohn.Forte@Sun.COM 	uint32_t	num_to_release, ndx;
30447836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
30457836SJohn.Forte@Sun.COM 	stmf_lu_t	*lu = ilu->ilu_lu;
30467836SJohn.Forte@Sun.COM 
30477836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free);
30487836SJohn.Forte@Sun.COM 
30497836SJohn.Forte@Sun.COM 	/* free half of the minimal free of the free tasks */
30507836SJohn.Forte@Sun.COM 	num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2;
30517836SJohn.Forte@Sun.COM 	if (!num_to_release) {
30527836SJohn.Forte@Sun.COM 		return;
30537836SJohn.Forte@Sun.COM 	}
30547836SJohn.Forte@Sun.COM 	for (ndx = 0; ndx < num_to_release; ndx++) {
30557836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
30567836SJohn.Forte@Sun.COM 		itask = ilu->ilu_free_tasks;
30577836SJohn.Forte@Sun.COM 		if (itask == NULL) {
30587836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
30597836SJohn.Forte@Sun.COM 			break;
30607836SJohn.Forte@Sun.COM 		}
30617836SJohn.Forte@Sun.COM 		ilu->ilu_free_tasks = itask->itask_lu_free_next;
30627836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_free--;
30637836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30647836SJohn.Forte@Sun.COM 
30657836SJohn.Forte@Sun.COM 		lu->lu_task_free(itask->itask_task);
30667836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
30677836SJohn.Forte@Sun.COM 		if (itask->itask_lu_next)
30687836SJohn.Forte@Sun.COM 			itask->itask_lu_next->itask_lu_prev =
30697836SJohn.Forte@Sun.COM 			    itask->itask_lu_prev;
30707836SJohn.Forte@Sun.COM 		if (itask->itask_lu_prev)
30717836SJohn.Forte@Sun.COM 			itask->itask_lu_prev->itask_lu_next =
30727836SJohn.Forte@Sun.COM 			    itask->itask_lu_next;
30737836SJohn.Forte@Sun.COM 		else
30747836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = itask->itask_lu_next;
30757836SJohn.Forte@Sun.COM 
30767836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks--;
30777836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30787836SJohn.Forte@Sun.COM 		stmf_free(itask->itask_task);
30797836SJohn.Forte@Sun.COM 	}
30807836SJohn.Forte@Sun.COM }
30817836SJohn.Forte@Sun.COM 
30827836SJohn.Forte@Sun.COM /*
30837836SJohn.Forte@Sun.COM  * Called with stmf_lock held
30847836SJohn.Forte@Sun.COM  */
30857836SJohn.Forte@Sun.COM void
30867836SJohn.Forte@Sun.COM stmf_check_freetask()
30877836SJohn.Forte@Sun.COM {
30887836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
30897836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
30907836SJohn.Forte@Sun.COM 
30917836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_draining may get changed after stmf_lock is released */
30927836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) {
30937836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
30947836SJohn.Forte@Sun.COM 		if (!ilu->ilu_ntasks_min_free) {
30957836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
30967836SJohn.Forte@Sun.COM 			continue;
30977836SJohn.Forte@Sun.COM 		}
30987836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
30997836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
31007836SJohn.Forte@Sun.COM 		stmf_task_lu_check_freelist(ilu);
31017836SJohn.Forte@Sun.COM 		/*
31027836SJohn.Forte@Sun.COM 		 * we do not care about the accuracy of
31037836SJohn.Forte@Sun.COM 		 * ilu_ntasks_min_free, so we don't lock here
31047836SJohn.Forte@Sun.COM 		 */
31057836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
31067836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
31077836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
31087836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
31097836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
31107836SJohn.Forte@Sun.COM 			break;
31117836SJohn.Forte@Sun.COM 	}
31127836SJohn.Forte@Sun.COM }
31137836SJohn.Forte@Sun.COM 
31147836SJohn.Forte@Sun.COM void
31157836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu)
31167836SJohn.Forte@Sun.COM {
31177836SJohn.Forte@Sun.COM 	clock_t l = ddi_get_lbolt();
31187836SJohn.Forte@Sun.COM 	clock_t ps = drv_usectohz(1000000);
31197836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
31207836SJohn.Forte@Sun.COM 	scsi_task_t *task;
31217836SJohn.Forte@Sun.COM 	uint32_t to;
31227836SJohn.Forte@Sun.COM 
31237836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
31247836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
31257836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
31267836SJohn.Forte@Sun.COM 		if (itask->itask_flags & (ITASK_IN_FREE_LIST |
31277836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) {
31287836SJohn.Forte@Sun.COM 			continue;
31297836SJohn.Forte@Sun.COM 		}
31307836SJohn.Forte@Sun.COM 		task = itask->itask_task;
31317836SJohn.Forte@Sun.COM 		if (task->task_timeout == 0)
31327836SJohn.Forte@Sun.COM 			to = stmf_default_task_timeout;
31337836SJohn.Forte@Sun.COM 		else
31347836SJohn.Forte@Sun.COM 			to = task->task_timeout;
31357836SJohn.Forte@Sun.COM 		if ((itask->itask_start_time + (to * ps)) > l)
31367836SJohn.Forte@Sun.COM 			continue;
31377836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
31387836SJohn.Forte@Sun.COM 		    STMF_TIMEOUT, NULL);
31397836SJohn.Forte@Sun.COM 	}
31407836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
31417836SJohn.Forte@Sun.COM }
31427836SJohn.Forte@Sun.COM 
31437836SJohn.Forte@Sun.COM /*
31447836SJohn.Forte@Sun.COM  * Called with stmf_lock held
31457836SJohn.Forte@Sun.COM  */
31467836SJohn.Forte@Sun.COM void
31477836SJohn.Forte@Sun.COM stmf_check_ilu_timing()
31487836SJohn.Forte@Sun.COM {
31497836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
31507836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
31517836SJohn.Forte@Sun.COM 
31527836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_timing may get changed after stmf_lock is released */
31537836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) {
31547836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
31557836SJohn.Forte@Sun.COM 		if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) {
31567836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr2 == 0) {
31577836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2;
31587836SJohn.Forte@Sun.COM 				continue;
31597836SJohn.Forte@Sun.COM 			}
31607836SJohn.Forte@Sun.COM 		} else {
31617836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr1 == 0) {
31627836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
31637836SJohn.Forte@Sun.COM 				continue;
31647836SJohn.Forte@Sun.COM 			}
31657836SJohn.Forte@Sun.COM 		}
31667836SJohn.Forte@Sun.COM 		/*
31677836SJohn.Forte@Sun.COM 		 * If we are here then it means that there is some slowdown
31687836SJohn.Forte@Sun.COM 		 * in tasks on this lu. We need to check.
31697836SJohn.Forte@Sun.COM 		 */
31707836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
31717836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
31727836SJohn.Forte@Sun.COM 		stmf_do_ilu_timeouts(ilu);
31737836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
31747836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
31757836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
31767836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
31777836SJohn.Forte@Sun.COM 			break;
31787836SJohn.Forte@Sun.COM 	}
31797836SJohn.Forte@Sun.COM }
31807836SJohn.Forte@Sun.COM 
31817836SJohn.Forte@Sun.COM /*
31827836SJohn.Forte@Sun.COM  * Kills all tasks on a lu except tm_task
31837836SJohn.Forte@Sun.COM  */
31847836SJohn.Forte@Sun.COM void
31857836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s)
31867836SJohn.Forte@Sun.COM {
31877836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
31887836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
31897836SJohn.Forte@Sun.COM 
31907836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
31917836SJohn.Forte@Sun.COM 
31927836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
31937836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
31947836SJohn.Forte@Sun.COM 		if (itask->itask_flags & ITASK_IN_FREE_LIST)
31957836SJohn.Forte@Sun.COM 			continue;
31967836SJohn.Forte@Sun.COM 		if (itask->itask_task == tm_task)
31977836SJohn.Forte@Sun.COM 			continue;
31987836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL);
31997836SJohn.Forte@Sun.COM 	}
32007836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
32017836SJohn.Forte@Sun.COM }
32027836SJohn.Forte@Sun.COM 
32037836SJohn.Forte@Sun.COM void
32047836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport)
32057836SJohn.Forte@Sun.COM {
32067836SJohn.Forte@Sun.COM 	int i;
32077836SJohn.Forte@Sun.COM 	uint8_t map;
32087836SJohn.Forte@Sun.COM 
32097836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
32107836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
32117836SJohn.Forte@Sun.COM 			if (map & 1) {
32127836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
32137836SJohn.Forte@Sun.COM 
32147836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
32157836SJohn.Forte@Sun.COM 				if (dbuf->db_lu_private) {
32167836SJohn.Forte@Sun.COM 					dbuf->db_lu_private = NULL;
32177836SJohn.Forte@Sun.COM 				}
32187836SJohn.Forte@Sun.COM 				lport->lport_ds->ds_free_data_buf(
32197836SJohn.Forte@Sun.COM 				    lport->lport_ds, dbuf);
32207836SJohn.Forte@Sun.COM 			}
32217836SJohn.Forte@Sun.COM 			map >>= 1;
32227836SJohn.Forte@Sun.COM 		}
32237836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
32247836SJohn.Forte@Sun.COM 	}
32257836SJohn.Forte@Sun.COM }
32267836SJohn.Forte@Sun.COM 
32277836SJohn.Forte@Sun.COM void
32287836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task)
32297836SJohn.Forte@Sun.COM {
32307836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
32317836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
32328662SJordan.Vaughan@Sun.com 	    task->task_stmf_private;
32337836SJohn.Forte@Sun.COM 
32348859STim.Szeto@Sun.COM 	DTRACE_PROBE1(stmf__task__end, scsi_task_t *, task);
32357836SJohn.Forte@Sun.COM 	stmf_free_task_bufs(itask, lport);
32367836SJohn.Forte@Sun.COM 	if (itask->itask_itl_datap) {
32377836SJohn.Forte@Sun.COM 		if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter,
32387836SJohn.Forte@Sun.COM 		    -1) == 0) {
32397836SJohn.Forte@Sun.COM 			stmf_release_itl_handle(task->task_lu,
32408662SJordan.Vaughan@Sun.com 			    itask->itask_itl_datap);
32417836SJohn.Forte@Sun.COM 		}
32427836SJohn.Forte@Sun.COM 	}
32437836SJohn.Forte@Sun.COM 	lport->lport_task_free(task);
32447836SJohn.Forte@Sun.COM 	if (itask->itask_worker) {
32457836SJohn.Forte@Sun.COM 		atomic_add_32(&stmf_cur_ntasks, -1);
32467836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_worker->worker_ref_count, -1);
32477836SJohn.Forte@Sun.COM 	}
32487836SJohn.Forte@Sun.COM 	/*
32497836SJohn.Forte@Sun.COM 	 * After calling stmf_task_lu_free, the task pointer can no longer
32507836SJohn.Forte@Sun.COM 	 * be trusted.
32517836SJohn.Forte@Sun.COM 	 */
32527836SJohn.Forte@Sun.COM 	stmf_task_lu_free(task);
32537836SJohn.Forte@Sun.COM }
32547836SJohn.Forte@Sun.COM 
32557836SJohn.Forte@Sun.COM void
32567836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
32577836SJohn.Forte@Sun.COM {
32587836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
32597836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
32607836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
32617836SJohn.Forte@Sun.COM 	int nv;
32627836SJohn.Forte@Sun.COM 	uint32_t old, new;
32637836SJohn.Forte@Sun.COM 	uint32_t ct;
32647836SJohn.Forte@Sun.COM 	stmf_worker_t *w, *w1;
32657836SJohn.Forte@Sun.COM 	uint8_t tm;
32667836SJohn.Forte@Sun.COM 
32677836SJohn.Forte@Sun.COM 	if (task->task_max_nbufs > 4)
32687836SJohn.Forte@Sun.COM 		task->task_max_nbufs = 4;
32697836SJohn.Forte@Sun.COM 	task->task_cur_nbufs = 0;
32707836SJohn.Forte@Sun.COM 	/* Latest value of currently running tasks */
32717836SJohn.Forte@Sun.COM 	ct = atomic_add_32_nv(&stmf_cur_ntasks, 1);
32727836SJohn.Forte@Sun.COM 
32737836SJohn.Forte@Sun.COM 	/* Select the next worker using round robin */
32747836SJohn.Forte@Sun.COM 	nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1);
32757836SJohn.Forte@Sun.COM 	if (nv >= stmf_nworkers_accepting_cmds) {
32767836SJohn.Forte@Sun.COM 		int s = nv;
32777836SJohn.Forte@Sun.COM 		do {
32787836SJohn.Forte@Sun.COM 			nv -= stmf_nworkers_accepting_cmds;
32797836SJohn.Forte@Sun.COM 		} while (nv >= stmf_nworkers_accepting_cmds);
32807836SJohn.Forte@Sun.COM 		if (nv < 0)
32817836SJohn.Forte@Sun.COM 			nv = 0;
32827836SJohn.Forte@Sun.COM 		/* Its ok if this cas fails */
32837836SJohn.Forte@Sun.COM 		(void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter,
32847836SJohn.Forte@Sun.COM 		    s, nv);
32857836SJohn.Forte@Sun.COM 	}
32867836SJohn.Forte@Sun.COM 	w = &stmf_workers[nv];
32877836SJohn.Forte@Sun.COM 
32887836SJohn.Forte@Sun.COM 	/*
32897836SJohn.Forte@Sun.COM 	 * A worker can be pinned by interrupt. So select the next one
32907836SJohn.Forte@Sun.COM 	 * if it has lower load.
32917836SJohn.Forte@Sun.COM 	 */
32927836SJohn.Forte@Sun.COM 	if ((nv + 1) >= stmf_nworkers_accepting_cmds) {
32937836SJohn.Forte@Sun.COM 		w1 = stmf_workers;
32947836SJohn.Forte@Sun.COM 	} else {
32957836SJohn.Forte@Sun.COM 		w1 = &stmf_workers[nv + 1];
32967836SJohn.Forte@Sun.COM 	}
32977836SJohn.Forte@Sun.COM 	if (w1->worker_queue_depth < w->worker_queue_depth)
32987836SJohn.Forte@Sun.COM 		w = w1;
32999435STim.Szeto@Sun.COM 
33007836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
33017836SJohn.Forte@Sun.COM 	if (((w->worker_flags & STMF_WORKER_STARTED) == 0) ||
33027836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
33037836SJohn.Forte@Sun.COM 		/*
33047836SJohn.Forte@Sun.COM 		 * Maybe we are in the middle of a change. Just go to
33057836SJohn.Forte@Sun.COM 		 * the 1st worker.
33067836SJohn.Forte@Sun.COM 		 */
33077836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
33087836SJohn.Forte@Sun.COM 		w = stmf_workers;
33097836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
33107836SJohn.Forte@Sun.COM 	}
33117836SJohn.Forte@Sun.COM 	itask->itask_worker = w;
33127836SJohn.Forte@Sun.COM 	/*
33137836SJohn.Forte@Sun.COM 	 * Track max system load inside the worker as we already have the
33147836SJohn.Forte@Sun.COM 	 * worker lock (no point implementing another lock). The service
33157836SJohn.Forte@Sun.COM 	 * thread will do the comparisons and figure out the max overall
33167836SJohn.Forte@Sun.COM 	 * system load.
33177836SJohn.Forte@Sun.COM 	 */
33187836SJohn.Forte@Sun.COM 	if (w->worker_max_sys_qdepth_pu < ct)
33197836SJohn.Forte@Sun.COM 		w->worker_max_sys_qdepth_pu = ct;
33207836SJohn.Forte@Sun.COM 
33217836SJohn.Forte@Sun.COM 	do {
33227836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
33237836SJohn.Forte@Sun.COM 		new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE;
33247836SJohn.Forte@Sun.COM 		if (task->task_mgmt_function) {
33257836SJohn.Forte@Sun.COM 			tm = task->task_mgmt_function;
33267836SJohn.Forte@Sun.COM 			if ((tm == TM_TARGET_RESET) ||
33277836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_COLD_RESET) ||
33287836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_WARM_RESET)) {
33297836SJohn.Forte@Sun.COM 				new |= ITASK_DEFAULT_HANDLING;
33307836SJohn.Forte@Sun.COM 			}
33317836SJohn.Forte@Sun.COM 		} else if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
33327836SJohn.Forte@Sun.COM 			new |= ITASK_DEFAULT_HANDLING;
33337836SJohn.Forte@Sun.COM 		}
33347836SJohn.Forte@Sun.COM 		new &= ~ITASK_IN_TRANSITION;
33357836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
33367836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
33377836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
33387836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
33397836SJohn.Forte@Sun.COM 	} else {
33407836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
33417836SJohn.Forte@Sun.COM 	}
33427836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
33437836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
33447836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
33457836SJohn.Forte@Sun.COM 	}
33467836SJohn.Forte@Sun.COM 	atomic_add_32(&w->worker_ref_count, 1);
33477836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK;
33487836SJohn.Forte@Sun.COM 	itask->itask_ncmds = 1;
33497836SJohn.Forte@Sun.COM 	if (dbuf) {
33507836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 1;
33517836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = dbuf;
33527836SJohn.Forte@Sun.COM 		dbuf->db_handle = 0;
33537836SJohn.Forte@Sun.COM 	} else {
33547836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
33557836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = NULL;
33567836SJohn.Forte@Sun.COM 	}
33579435STim.Szeto@Sun.COM 
33589435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_q(task, kstat_waitq_enter);
33599435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_q(task, kstat_waitq_enter);
33609435STim.Szeto@Sun.COM 
33617836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
33627836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
33637836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
33647836SJohn.Forte@Sun.COM 
33657836SJohn.Forte@Sun.COM 	/*
33667836SJohn.Forte@Sun.COM 	 * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE
33677836SJohn.Forte@Sun.COM 	 * was set between checking of ILU_RESET_ACTIVE and clearing of the
33687836SJohn.Forte@Sun.COM 	 * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here.
33697836SJohn.Forte@Sun.COM 	 */
33707836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
33717836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL);
33727836SJohn.Forte@Sun.COM 	}
33737836SJohn.Forte@Sun.COM }
33747836SJohn.Forte@Sun.COM 
33757836SJohn.Forte@Sun.COM /*
33767836SJohn.Forte@Sun.COM  * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++
33777836SJohn.Forte@Sun.COM  * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already
33787836SJohn.Forte@Sun.COM  * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot
33797836SJohn.Forte@Sun.COM  * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course
33807836SJohn.Forte@Sun.COM  * the LU will make this call only if we call the LU's abort entry point.
33817836SJohn.Forte@Sun.COM  * we will only call that entry point if ITASK_KNOWN_TO_LU was set.
33827836SJohn.Forte@Sun.COM  *
33837836SJohn.Forte@Sun.COM  * Same logic applies for the port.
33847836SJohn.Forte@Sun.COM  *
33857836SJohn.Forte@Sun.COM  * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU
33867836SJohn.Forte@Sun.COM  * and KNOWN_TO_TGT_PORT are reset.
33877836SJohn.Forte@Sun.COM  *
33887836SJohn.Forte@Sun.COM  * +++++++++++++++++++++++++++++++++++++++++++++++
33897836SJohn.Forte@Sun.COM  */
33907836SJohn.Forte@Sun.COM 
33917836SJohn.Forte@Sun.COM stmf_status_t
33927836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
33937836SJohn.Forte@Sun.COM {
33948859STim.Szeto@Sun.COM 	stmf_status_t ret;
33958859STim.Szeto@Sun.COM 
33967836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
33977836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
33987836SJohn.Forte@Sun.COM 
33997836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
34007836SJohn.Forte@Sun.COM 		uint32_t new, old;
34017836SJohn.Forte@Sun.COM 		do {
34027836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
34037836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
34047836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
34057836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
34067836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34077836SJohn.Forte@Sun.COM 	}
34087836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
34097836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
34107836SJohn.Forte@Sun.COM #ifdef	DEBUG
34117836SJohn.Forte@Sun.COM 	if (stmf_drop_buf_counter > 0) {
34128662SJordan.Vaughan@Sun.com 		if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) ==
34138662SJordan.Vaughan@Sun.com 		    1)
34147836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
34157836SJohn.Forte@Sun.COM 	}
34167836SJohn.Forte@Sun.COM #endif
34179435STim.Szeto@Sun.COM 
34189435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_io(task, dbuf);
34199435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_io(task, dbuf);
34209435STim.Szeto@Sun.COM 
34218859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, task,
34228859STim.Szeto@Sun.COM 	    stmf_data_buf_t *, dbuf);
34238859STim.Szeto@Sun.COM 	ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags);
34248859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__xfer__end, scsi_task_t *, task,
34258859STim.Szeto@Sun.COM 	    stmf_data_buf_t *, dbuf);
34268859STim.Szeto@Sun.COM 	return (ret);
34277836SJohn.Forte@Sun.COM }
34287836SJohn.Forte@Sun.COM 
34297836SJohn.Forte@Sun.COM void
34307836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof)
34317836SJohn.Forte@Sun.COM {
34327836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
34337836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
34347836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
34357836SJohn.Forte@Sun.COM 	uint32_t new, old;
34367836SJohn.Forte@Sun.COM 	uint8_t update_queue_flags, free_it, queue_it;
34377836SJohn.Forte@Sun.COM 
34387836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
34397836SJohn.Forte@Sun.COM 	do {
34407836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
34417836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
34427836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
34437836SJohn.Forte@Sun.COM 			return;
34447836SJohn.Forte@Sun.COM 		}
34457836SJohn.Forte@Sun.COM 		free_it = 0;
34467836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
34477836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
34487836SJohn.Forte@Sun.COM 			task->task_completion_status = dbuf->db_xfer_status;
34497836SJohn.Forte@Sun.COM 			free_it = 1;
34507836SJohn.Forte@Sun.COM 		}
34517836SJohn.Forte@Sun.COM 		/*
34527836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
34537836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
34547836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
34557836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
34567836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
34577836SJohn.Forte@Sun.COM 		 * free this task.
34587836SJohn.Forte@Sun.COM 		 */
34597836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
34607836SJohn.Forte@Sun.COM 			free_it = 0;
34617836SJohn.Forte@Sun.COM 			update_queue_flags = 1;
34627836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
34637836SJohn.Forte@Sun.COM 				queue_it = 0;
34647836SJohn.Forte@Sun.COM 			} else {
34657836SJohn.Forte@Sun.COM 				queue_it = 1;
34667836SJohn.Forte@Sun.COM 				new |= ITASK_IN_WORKER_QUEUE;
34677836SJohn.Forte@Sun.COM 			}
34687836SJohn.Forte@Sun.COM 		} else {
34697836SJohn.Forte@Sun.COM 			update_queue_flags = 0;
34707836SJohn.Forte@Sun.COM 			queue_it = 0;
34717836SJohn.Forte@Sun.COM 		}
34727836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34737836SJohn.Forte@Sun.COM 
34747836SJohn.Forte@Sun.COM 	if (update_queue_flags) {
34757836SJohn.Forte@Sun.COM 		uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE;
34767836SJohn.Forte@Sun.COM 
34777836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
34787836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] = cmd;
34797836SJohn.Forte@Sun.COM 		if (queue_it) {
34807836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
34817836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
34827836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
34837836SJohn.Forte@Sun.COM 			} else {
34847836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
34857836SJohn.Forte@Sun.COM 			}
34867836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
34877836SJohn.Forte@Sun.COM 			if (++(w->worker_queue_depth) >
34887836SJohn.Forte@Sun.COM 			    w->worker_max_qdepth_pu) {
34897836SJohn.Forte@Sun.COM 				w->worker_max_qdepth_pu = w->worker_queue_depth;
34907836SJohn.Forte@Sun.COM 			}
34917836SJohn.Forte@Sun.COM 			if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
34927836SJohn.Forte@Sun.COM 				cv_signal(&w->worker_cv);
34937836SJohn.Forte@Sun.COM 		}
34947836SJohn.Forte@Sun.COM 	}
34957836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
34967836SJohn.Forte@Sun.COM 
34977836SJohn.Forte@Sun.COM 	if (free_it) {
34987836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
34997836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
35007836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
35019435STim.Szeto@Sun.COM 			stmf_update_kstat_lu_q(task, kstat_runq_exit);
35029435STim.Szeto@Sun.COM 			stmf_update_kstat_lport_q(task, kstat_runq_exit);
35037836SJohn.Forte@Sun.COM 			stmf_task_free(task);
35047836SJohn.Forte@Sun.COM 		}
35057836SJohn.Forte@Sun.COM 	}
35067836SJohn.Forte@Sun.COM }
35077836SJohn.Forte@Sun.COM 
35087836SJohn.Forte@Sun.COM stmf_status_t
35097836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
35107836SJohn.Forte@Sun.COM {
35118859STim.Szeto@Sun.COM 	DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task);
35128859STim.Szeto@Sun.COM 
35137836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
35148662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
35157836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
35167836SJohn.Forte@Sun.COM 		uint32_t new, old;
35177836SJohn.Forte@Sun.COM 		do {
35187836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
35197836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
35207836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
35217836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
35227836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
35237836SJohn.Forte@Sun.COM 	}
35247836SJohn.Forte@Sun.COM 
35257836SJohn.Forte@Sun.COM 	if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) {
35267836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
35277836SJohn.Forte@Sun.COM 	}
35287836SJohn.Forte@Sun.COM 
35297836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
35307836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
35317836SJohn.Forte@Sun.COM 
35327836SJohn.Forte@Sun.COM 	if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) {
35337836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
35347836SJohn.Forte@Sun.COM 		task->task_resid = 0;
35357836SJohn.Forte@Sun.COM 	} else if (task->task_cmd_xfer_length >
35367836SJohn.Forte@Sun.COM 	    task->task_expected_xfer_length) {
35377836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_OVER;
35387836SJohn.Forte@Sun.COM 		task->task_resid = task->task_cmd_xfer_length -
35398662SJordan.Vaughan@Sun.com 		    task->task_expected_xfer_length;
35407836SJohn.Forte@Sun.COM 	} else if (task->task_nbytes_transferred <
35418662SJordan.Vaughan@Sun.com 	    task->task_expected_xfer_length) {
35427836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_UNDER;
35437836SJohn.Forte@Sun.COM 		task->task_resid = task->task_expected_xfer_length -
35448662SJordan.Vaughan@Sun.com 		    task->task_nbytes_transferred;
35457836SJohn.Forte@Sun.COM 	} else {
35467836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
35477836SJohn.Forte@Sun.COM 		task->task_resid = 0;
35487836SJohn.Forte@Sun.COM 	}
35497836SJohn.Forte@Sun.COM 	return (task->task_lport->lport_send_status(task, ioflags));
35507836SJohn.Forte@Sun.COM }
35517836SJohn.Forte@Sun.COM 
35527836SJohn.Forte@Sun.COM void
35537836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof)
35547836SJohn.Forte@Sun.COM {
35557836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
35567836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
35577836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
35587836SJohn.Forte@Sun.COM 	uint32_t new, old;
35597836SJohn.Forte@Sun.COM 	uint8_t free_it, queue_it;
35607836SJohn.Forte@Sun.COM 
35617836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
35627836SJohn.Forte@Sun.COM 	do {
35637836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
35647836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
35657836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
35667836SJohn.Forte@Sun.COM 			return;
35677836SJohn.Forte@Sun.COM 		}
35687836SJohn.Forte@Sun.COM 		free_it = 0;
35697836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
35707836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
35717836SJohn.Forte@Sun.COM 			free_it = 1;
35727836SJohn.Forte@Sun.COM 		}
35737836SJohn.Forte@Sun.COM 		/*
35747836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
35757836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
35767836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
35777836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
35787836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
35797836SJohn.Forte@Sun.COM 		 * free this task.
35807836SJohn.Forte@Sun.COM 		 */
35817836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
35827836SJohn.Forte@Sun.COM 			free_it = 0;
35837836SJohn.Forte@Sun.COM 			queue_it = 1;
35847836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
35857836SJohn.Forte@Sun.COM 				cmn_err(CE_PANIC, "status completion received"
35867836SJohn.Forte@Sun.COM 				    " when task is already in worker queue "
35877836SJohn.Forte@Sun.COM 				    " task = %p", (void *)task);
35887836SJohn.Forte@Sun.COM 			}
35897836SJohn.Forte@Sun.COM 			new |= ITASK_IN_WORKER_QUEUE;
35907836SJohn.Forte@Sun.COM 		} else {
35917836SJohn.Forte@Sun.COM 			queue_it = 0;
35927836SJohn.Forte@Sun.COM 		}
35937836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
35947836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
35957836SJohn.Forte@Sun.COM 
35969435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_q(task, kstat_runq_exit);
35979435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_q(task, kstat_runq_exit);
35989435STim.Szeto@Sun.COM 
35997836SJohn.Forte@Sun.COM 	if (queue_it) {
36007836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
36017836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] =
36027836SJohn.Forte@Sun.COM 		    ITASK_CMD_STATUS_DONE;
36037836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
36047836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
36057836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
36067836SJohn.Forte@Sun.COM 		} else {
36077836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
36087836SJohn.Forte@Sun.COM 		}
36097836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
36107836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
36117836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
36127836SJohn.Forte@Sun.COM 		}
36137836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
36147836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
36157836SJohn.Forte@Sun.COM 	}
36167836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
36177836SJohn.Forte@Sun.COM 
36187836SJohn.Forte@Sun.COM 	if (free_it) {
36197836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
36207836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
36217836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
36227836SJohn.Forte@Sun.COM 			stmf_task_free(task);
36237836SJohn.Forte@Sun.COM 		} else {
36247836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "LU is done with the task but LPORT "
36257836SJohn.Forte@Sun.COM 			    " is not done, itask %p", (void *)itask);
36267836SJohn.Forte@Sun.COM 		}
36277836SJohn.Forte@Sun.COM 	}
36287836SJohn.Forte@Sun.COM }
36297836SJohn.Forte@Sun.COM 
36307836SJohn.Forte@Sun.COM void
36317836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task)
36327836SJohn.Forte@Sun.COM {
36337836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
36348662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
36357836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
36367836SJohn.Forte@Sun.COM 	uint32_t new, old;
36377836SJohn.Forte@Sun.COM 
36387836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
36397836SJohn.Forte@Sun.COM 	do {
36407836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
36417836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
36427836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
36437836SJohn.Forte@Sun.COM 			return;
36447836SJohn.Forte@Sun.COM 		}
36457836SJohn.Forte@Sun.COM 		if (old & ITASK_IN_WORKER_QUEUE) {
36467836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "task_lu_done received"
36477836SJohn.Forte@Sun.COM 			    " when task is in worker queue "
36487836SJohn.Forte@Sun.COM 			    " task = %p", (void *)task);
36497836SJohn.Forte@Sun.COM 		}
36507836SJohn.Forte@Sun.COM 		new &= ~ITASK_KNOWN_TO_LU;
36517836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
36527836SJohn.Forte@Sun.COM 
36537836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
36547836SJohn.Forte@Sun.COM 
36557836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
36567836SJohn.Forte@Sun.COM 	    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
36577836SJohn.Forte@Sun.COM 	    ITASK_BEING_ABORTED)) == 0) {
36587836SJohn.Forte@Sun.COM 		stmf_task_free(task);
36597836SJohn.Forte@Sun.COM 	} else {
36607836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but "
36617836SJohn.Forte@Sun.COM 		    " the task is still not done, task = %p", (void *)task);
36627836SJohn.Forte@Sun.COM 	}
36637836SJohn.Forte@Sun.COM }
36647836SJohn.Forte@Sun.COM 
36657836SJohn.Forte@Sun.COM void
36667836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s)
36677836SJohn.Forte@Sun.COM {
36687836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
36697836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
36707836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
36717836SJohn.Forte@Sun.COM 	uint32_t old, new;
36727836SJohn.Forte@Sun.COM 
36737836SJohn.Forte@Sun.COM 	do {
36747836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
36757836SJohn.Forte@Sun.COM 		if ((old & ITASK_BEING_ABORTED) ||
36767836SJohn.Forte@Sun.COM 		    ((old & (ITASK_KNOWN_TO_TGT_PORT |
36777836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU)) == 0)) {
36787836SJohn.Forte@Sun.COM 			return;
36797836SJohn.Forte@Sun.COM 		}
36807836SJohn.Forte@Sun.COM 		new |= ITASK_BEING_ABORTED;
36817836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
36827836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
36837836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
36847836SJohn.Forte@Sun.COM 
36857836SJohn.Forte@Sun.COM 	if (((w = itask->itask_worker) == NULL) ||
36867836SJohn.Forte@Sun.COM 	    (itask->itask_flags & ITASK_IN_TRANSITION)) {
36877836SJohn.Forte@Sun.COM 		return;
36887836SJohn.Forte@Sun.COM 	}
36897836SJohn.Forte@Sun.COM 
36907836SJohn.Forte@Sun.COM 	/* Queue it and get out */
36917836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
36927836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) {
36937836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
36947836SJohn.Forte@Sun.COM 		return;
36957836SJohn.Forte@Sun.COM 	}
36967836SJohn.Forte@Sun.COM 	atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
36977836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
36987836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
36997836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
37007836SJohn.Forte@Sun.COM 	} else {
37017836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
37027836SJohn.Forte@Sun.COM 	}
37037836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
37047836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
37057836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
37067836SJohn.Forte@Sun.COM 	}
37077836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
37087836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
37097836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
37107836SJohn.Forte@Sun.COM }
37117836SJohn.Forte@Sun.COM 
37127836SJohn.Forte@Sun.COM void
37137836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg)
37147836SJohn.Forte@Sun.COM {
37157836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = NULL;
37167836SJohn.Forte@Sun.COM 	uint32_t old, new, f, rf;
37177836SJohn.Forte@Sun.COM 
37188859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task,
37198859STim.Szeto@Sun.COM 	    stmf_status_t, s);
37208859STim.Szeto@Sun.COM 
37217836SJohn.Forte@Sun.COM 	switch (abort_cmd) {
37227836SJohn.Forte@Sun.COM 	case STMF_QUEUE_ABORT_LU:
37237836SJohn.Forte@Sun.COM 		stmf_task_lu_killall((stmf_lu_t *)arg, task, s);
37247836SJohn.Forte@Sun.COM 		return;
37257836SJohn.Forte@Sun.COM 	case STMF_QUEUE_TASK_ABORT:
37267836SJohn.Forte@Sun.COM 		stmf_queue_task_for_abort(task, s);
37277836SJohn.Forte@Sun.COM 		return;
37287836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LPORT:
37297836SJohn.Forte@Sun.COM 		rf = ITASK_TGT_PORT_ABORT_CALLED;
37307836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_TGT_PORT;
37317836SJohn.Forte@Sun.COM 		break;
37327836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LU:
37337836SJohn.Forte@Sun.COM 		rf = ITASK_LU_ABORT_CALLED;
37347836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_LU;
37357836SJohn.Forte@Sun.COM 		break;
37367836SJohn.Forte@Sun.COM 	default:
37377836SJohn.Forte@Sun.COM 		return;
37387836SJohn.Forte@Sun.COM 	}
37397836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
37407836SJohn.Forte@Sun.COM 	f |= ITASK_BEING_ABORTED | rf;
37417836SJohn.Forte@Sun.COM 	do {
37427836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
37437836SJohn.Forte@Sun.COM 		if ((old & f) != f) {
37447836SJohn.Forte@Sun.COM 			return;
37457836SJohn.Forte@Sun.COM 		}
37467836SJohn.Forte@Sun.COM 		new &= ~rf;
37477836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
37487836SJohn.Forte@Sun.COM }
37497836SJohn.Forte@Sun.COM 
37507836SJohn.Forte@Sun.COM void
37517836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
37527836SJohn.Forte@Sun.COM {
37537836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
37547836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
37557836SJohn.Forte@Sun.COM 	unsigned long long	st;
37567836SJohn.Forte@Sun.COM 
37577836SJohn.Forte@Sun.COM 	st = s;	/* gcc fix */
37587836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
37597836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37607836SJohn.Forte@Sun.COM 		    "task %p, lu failed to abort ret=%llx", (void *)task, st);
37617836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LU_DONE) == 0) {
37627836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37637836SJohn.Forte@Sun.COM 		    "Task aborted but LU is not finished, task ="
37647836SJohn.Forte@Sun.COM 		    "%p, s=%llx, iof=%x", (void *)task, st, iof);
37657836SJohn.Forte@Sun.COM 	} else {
37667836SJohn.Forte@Sun.COM 		/*
37677836SJohn.Forte@Sun.COM 		 * LU abort successfully
37687836SJohn.Forte@Sun.COM 		 */
37697836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU);
37707836SJohn.Forte@Sun.COM 		return;
37717836SJohn.Forte@Sun.COM 	}
37727836SJohn.Forte@Sun.COM 
37737836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
37747836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 1, info);
37757836SJohn.Forte@Sun.COM }
37767836SJohn.Forte@Sun.COM 
37777836SJohn.Forte@Sun.COM void
37787836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
37797836SJohn.Forte@Sun.COM {
37807836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
37817836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
37827836SJohn.Forte@Sun.COM 	unsigned long long	st;
37837836SJohn.Forte@Sun.COM 
37847836SJohn.Forte@Sun.COM 	st = s;
37857836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
37867836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37877836SJohn.Forte@Sun.COM 		    "task %p, tgt port failed to abort ret=%llx", (void *)task,
37887836SJohn.Forte@Sun.COM 		    st);
37897836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LPORT_DONE) == 0) {
37907836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37917836SJohn.Forte@Sun.COM 		    "Task aborted but tgt port is not finished, "
37927836SJohn.Forte@Sun.COM 		    "task=%p, s=%llx, iof=%x", (void *)task, st, iof);
37937836SJohn.Forte@Sun.COM 	} else {
37947836SJohn.Forte@Sun.COM 		/*
37957836SJohn.Forte@Sun.COM 		 * LU abort successfully
37967836SJohn.Forte@Sun.COM 		 */
37977836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT);
37987836SJohn.Forte@Sun.COM 		return;
37997836SJohn.Forte@Sun.COM 	}
38007836SJohn.Forte@Sun.COM 
38017836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
38027836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 0, info);
38037836SJohn.Forte@Sun.COM }
38047836SJohn.Forte@Sun.COM 
38057836SJohn.Forte@Sun.COM stmf_status_t
38067836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout)
38077836SJohn.Forte@Sun.COM {
38087836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
38097836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
38107836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
38117836SJohn.Forte@Sun.COM 	int i;
38127836SJohn.Forte@Sun.COM 
38137836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU);
38147836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
38157836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
38167836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
38177836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
38187836SJohn.Forte@Sun.COM 	}
38197836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
38207836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) {
38217836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
38227836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
38237836SJohn.Forte@Sun.COM 		}
38247836SJohn.Forte@Sun.COM 	}
38257836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU;
38267836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
38277836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
38287836SJohn.Forte@Sun.COM 	} else {
38297836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
38307836SJohn.Forte@Sun.COM 		if (t == 0)
38317836SJohn.Forte@Sun.COM 			t = 1;
38327836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
38337836SJohn.Forte@Sun.COM 	}
38347836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
38357836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
38367836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
38377836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
38387836SJohn.Forte@Sun.COM 		} else {
38397836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
38407836SJohn.Forte@Sun.COM 		}
38417836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
38427836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
38437836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
38447836SJohn.Forte@Sun.COM 		}
38457836SJohn.Forte@Sun.COM 		atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
38467836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
38477836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
38487836SJohn.Forte@Sun.COM 	}
38497836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
38507836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
38517836SJohn.Forte@Sun.COM }
38527836SJohn.Forte@Sun.COM 
38537836SJohn.Forte@Sun.COM stmf_status_t
38547836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout)
38557836SJohn.Forte@Sun.COM {
38567836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
38577836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
38587836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
38597836SJohn.Forte@Sun.COM 	int i;
38607836SJohn.Forte@Sun.COM 
38617836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT);
38627836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
38637836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
38647836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
38657836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
38667836SJohn.Forte@Sun.COM 	}
38677836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
38687836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) {
38697836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
38707836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
38717836SJohn.Forte@Sun.COM 		}
38727836SJohn.Forte@Sun.COM 	}
38737836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT;
38747836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
38757836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
38767836SJohn.Forte@Sun.COM 	} else {
38777836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
38787836SJohn.Forte@Sun.COM 		if (t == 0)
38797836SJohn.Forte@Sun.COM 			t = 1;
38807836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
38817836SJohn.Forte@Sun.COM 	}
38827836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
38837836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
38847836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
38857836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
38867836SJohn.Forte@Sun.COM 		} else {
38877836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
38887836SJohn.Forte@Sun.COM 		}
38897836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
38907836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
38917836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
38927836SJohn.Forte@Sun.COM 		}
38937836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
38947836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
38957836SJohn.Forte@Sun.COM 	}
38967836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
38977836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
38987836SJohn.Forte@Sun.COM }
38997836SJohn.Forte@Sun.COM 
39007836SJohn.Forte@Sun.COM void
39017836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task)
39027836SJohn.Forte@Sun.COM {
39037836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
39047836SJohn.Forte@Sun.COM 	stmf_lu_t		*lu;
39057836SJohn.Forte@Sun.COM 	stmf_local_port_t	*lport;
39067836SJohn.Forte@Sun.COM 	unsigned long long	 ret;
39077836SJohn.Forte@Sun.COM 	uint32_t		 old, new;
39087836SJohn.Forte@Sun.COM 	uint8_t			 call_lu_abort, call_port_abort;
39097836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
39107836SJohn.Forte@Sun.COM 
39117836SJohn.Forte@Sun.COM 	lu = task->task_lu;
39127836SJohn.Forte@Sun.COM 	lport = task->task_lport;
39137836SJohn.Forte@Sun.COM 	do {
39147836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
39157836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) ==
39167836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU) {
39177836SJohn.Forte@Sun.COM 			new |= ITASK_LU_ABORT_CALLED;
39187836SJohn.Forte@Sun.COM 			call_lu_abort = 1;
39197836SJohn.Forte@Sun.COM 		} else {
39207836SJohn.Forte@Sun.COM 			call_lu_abort = 0;
39217836SJohn.Forte@Sun.COM 		}
39227836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
39237836SJohn.Forte@Sun.COM 
39247836SJohn.Forte@Sun.COM 	if (call_lu_abort) {
39257836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) {
39267836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
39277836SJohn.Forte@Sun.COM 		} else {
39287836SJohn.Forte@Sun.COM 			ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
39297836SJohn.Forte@Sun.COM 		}
39307836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
39317836SJohn.Forte@Sun.COM 			stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE);
39327836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
39337836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
39347836SJohn.Forte@Sun.COM 			    ~ITASK_LU_ABORT_CALLED);
39357836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
39367836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39377836SJohn.Forte@Sun.COM 			    "Abort failed by LU %p, ret %llx", (void *)lu, ret);
39387836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39397836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 1, info);
39407836SJohn.Forte@Sun.COM 		}
39417836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_LU) {
39427836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
39437836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lu->lu_abort_timeout?
39447836SJohn.Forte@Sun.COM 		    lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) {
39457836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39467836SJohn.Forte@Sun.COM 			    "lu abort timed out");
39477836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39487836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 1, info);
39497836SJohn.Forte@Sun.COM 		}
39507836SJohn.Forte@Sun.COM 	}
39517836SJohn.Forte@Sun.COM 
39527836SJohn.Forte@Sun.COM 	do {
39537836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
39547836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_TGT_PORT |
39557836SJohn.Forte@Sun.COM 		    ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) {
39567836SJohn.Forte@Sun.COM 			new |= ITASK_TGT_PORT_ABORT_CALLED;
39577836SJohn.Forte@Sun.COM 			call_port_abort = 1;
39587836SJohn.Forte@Sun.COM 		} else {
39597836SJohn.Forte@Sun.COM 			call_port_abort = 0;
39607836SJohn.Forte@Sun.COM 		}
39617836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
39627836SJohn.Forte@Sun.COM 	if (call_port_abort) {
39638662SJordan.Vaughan@Sun.com 		ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0);
39647836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
39657836SJohn.Forte@Sun.COM 			stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE);
39667836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
39677836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
39687836SJohn.Forte@Sun.COM 			    ~ITASK_TGT_PORT_ABORT_CALLED);
39697836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
39707836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39717836SJohn.Forte@Sun.COM 			    "Abort failed by tgt port %p ret %llx",
39727836SJohn.Forte@Sun.COM 			    (void *)lport, ret);
39737836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39747836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 0, info);
39757836SJohn.Forte@Sun.COM 		}
39767836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) {
39777836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
39787836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lport->lport_abort_timeout?
39797836SJohn.Forte@Sun.COM 		    lport->lport_abort_timeout :
39807836SJohn.Forte@Sun.COM 		    ITASK_DEFAULT_ABORT_TIMEOUT))) {
39817836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39827836SJohn.Forte@Sun.COM 			    "lport abort timed out");
39837836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39847836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 0, info);
39857836SJohn.Forte@Sun.COM 		}
39867836SJohn.Forte@Sun.COM 	}
39877836SJohn.Forte@Sun.COM }
39887836SJohn.Forte@Sun.COM 
39897836SJohn.Forte@Sun.COM stmf_status_t
39907836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg)
39917836SJohn.Forte@Sun.COM {
39927836SJohn.Forte@Sun.COM 	stmf_status_t			ret;
39937836SJohn.Forte@Sun.COM 	stmf_i_lu_t			*ilu;
39947836SJohn.Forte@Sun.COM 	stmf_i_local_port_t		*ilport;
39957836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
39967836SJohn.Forte@Sun.COM 
39977836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
39987836SJohn.Forte@Sun.COM 	ret = STMF_INVALID_ARG;
39997836SJohn.Forte@Sun.COM 	if (cmd & STMF_CMD_LU_OP) {
40007836SJohn.Forte@Sun.COM 		ilu = stmf_lookup_lu((stmf_lu_t *)obj);
40017836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
40027836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40037836SJohn.Forte@Sun.COM 		}
40048859STim.Szeto@Sun.COM 		DTRACE_PROBE3(lu__state__change,
40058859STim.Szeto@Sun.COM 		    stmf_lu_t *, ilu->ilu_lu,
40068859STim.Szeto@Sun.COM 		    int, cmd, stmf_state_change_info_t *, ssci);
40077836SJohn.Forte@Sun.COM 	} else if (cmd & STMF_CMD_LPORT_OP) {
40087836SJohn.Forte@Sun.COM 		ilport = stmf_lookup_lport((stmf_local_port_t *)obj);
40097836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
40107836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40117836SJohn.Forte@Sun.COM 		}
40128859STim.Szeto@Sun.COM 		DTRACE_PROBE3(lport__state__change,
40138859STim.Szeto@Sun.COM 		    stmf_local_port_t *, ilport->ilport_lport,
40148859STim.Szeto@Sun.COM 		    int, cmd, stmf_state_change_info_t *, ssci);
40157836SJohn.Forte@Sun.COM 	} else {
40167836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
40177836SJohn.Forte@Sun.COM 	}
40187836SJohn.Forte@Sun.COM 
40197836SJohn.Forte@Sun.COM 	switch (cmd) {
40207836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE:
40217836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_ONLINE) {
40227836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
40237836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40247836SJohn.Forte@Sun.COM 		}
40257836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINE) {
40267836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40277836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40287836SJohn.Forte@Sun.COM 		}
40297836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_ONLINING;
40307836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40317836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
40327836SJohn.Forte@Sun.COM 		break;
40337836SJohn.Forte@Sun.COM 
40347836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE_COMPLETE:
40357836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINING) {
40367836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40377836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40387836SJohn.Forte@Sun.COM 		}
40397836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
40407836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
40417836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
40427836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
40437836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
40447836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_ONLINE_COMPLETE, arg);
40457836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
40467836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
40477836SJohn.Forte@Sun.COM 		} else {
40487836SJohn.Forte@Sun.COM 			/* XXX: should throw a meesage an record more data */
40497836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
40507836SJohn.Forte@Sun.COM 		}
40517836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
40527836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
40537836SJohn.Forte@Sun.COM 
40547836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE:
40557836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE) {
40567836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
40577836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40587836SJohn.Forte@Sun.COM 		}
40597836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE) {
40607836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40617836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40627836SJohn.Forte@Sun.COM 		}
40637836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_OFFLINING;
40647836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40657836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
40667836SJohn.Forte@Sun.COM 		break;
40677836SJohn.Forte@Sun.COM 
40687836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE_COMPLETE:
40697836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINING) {
40707836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40717836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40727836SJohn.Forte@Sun.COM 		}
40737836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
40747836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
40757836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
40767836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
40777836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
40787836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_OFFLINE_COMPLETE, arg);
40797836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
40807836SJohn.Forte@Sun.COM 		} else {
40817836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
40827836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
40837836SJohn.Forte@Sun.COM 		}
40847836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40857836SJohn.Forte@Sun.COM 		break;
40867836SJohn.Forte@Sun.COM 
40877836SJohn.Forte@Sun.COM 	/*
40887836SJohn.Forte@Sun.COM 	 * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online.
40897836SJohn.Forte@Sun.COM 	 * It's related with hardware disable/enable.
40907836SJohn.Forte@Sun.COM 	 */
40917836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE:
40927836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_ONLINE) {
40937836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
40947836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40957836SJohn.Forte@Sun.COM 		}
40967836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINE) {
40977836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40987836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40997836SJohn.Forte@Sun.COM 		}
41007836SJohn.Forte@Sun.COM 
41017836SJohn.Forte@Sun.COM 		/*
41027836SJohn.Forte@Sun.COM 		 * Only user request can recover the port from the
41037836SJohn.Forte@Sun.COM 		 * FORCED_OFFLINE state
41047836SJohn.Forte@Sun.COM 		 */
41057836SJohn.Forte@Sun.COM 		if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) {
41067836SJohn.Forte@Sun.COM 			if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) {
41077836SJohn.Forte@Sun.COM 				ret = STMF_FAILURE;
41087836SJohn.Forte@Sun.COM 				goto stmf_ctl_lock_exit;
41097836SJohn.Forte@Sun.COM 			}
41107836SJohn.Forte@Sun.COM 		}
41117836SJohn.Forte@Sun.COM 
41127836SJohn.Forte@Sun.COM 		/*
41137836SJohn.Forte@Sun.COM 		 * Avoid too frequent request to online
41147836SJohn.Forte@Sun.COM 		 */
41157836SJohn.Forte@Sun.COM 		if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
41167836SJohn.Forte@Sun.COM 			ilport->ilport_online_times = 0;
41177836SJohn.Forte@Sun.COM 			ilport->ilport_avg_interval = 0;
41187836SJohn.Forte@Sun.COM 		}
41197836SJohn.Forte@Sun.COM 		if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) &&
41207836SJohn.Forte@Sun.COM 		    (ilport->ilport_online_times >= 4)) {
41217836SJohn.Forte@Sun.COM 			ret = STMF_FAILURE;
41227836SJohn.Forte@Sun.COM 			ilport->ilport_flags |= ILPORT_FORCED_OFFLINE;
41237836SJohn.Forte@Sun.COM 			stmf_trace(NULL, "stmf_ctl: too frequent request to "
41247836SJohn.Forte@Sun.COM 			    "online the port");
41257836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "stmf_ctl: too frequent request to "
41267836SJohn.Forte@Sun.COM 			    "online the port, set FORCED_OFFLINE now");
41277836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41287836SJohn.Forte@Sun.COM 		}
41297836SJohn.Forte@Sun.COM 		if (ilport->ilport_online_times > 0) {
41307836SJohn.Forte@Sun.COM 			if (ilport->ilport_online_times == 1) {
41317836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval = ddi_get_lbolt() -
41327836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock;
41337836SJohn.Forte@Sun.COM 			} else {
41347836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval =
41357836SJohn.Forte@Sun.COM 				    (ilport->ilport_avg_interval +
41367836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() -
41377836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock) >> 1;
41387836SJohn.Forte@Sun.COM 			}
41397836SJohn.Forte@Sun.COM 		}
41407836SJohn.Forte@Sun.COM 		ilport->ilport_last_online_clock = ddi_get_lbolt();
41417836SJohn.Forte@Sun.COM 		ilport->ilport_online_times++;
41427836SJohn.Forte@Sun.COM 
41437836SJohn.Forte@Sun.COM 		/*
41447836SJohn.Forte@Sun.COM 		 * Submit online service request
41457836SJohn.Forte@Sun.COM 		 */
41467836SJohn.Forte@Sun.COM 		ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE;
41477836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_ONLINING;
41487836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41497836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
41507836SJohn.Forte@Sun.COM 		break;
41517836SJohn.Forte@Sun.COM 
41527836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE_COMPLETE:
41537836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINING) {
41547836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41557836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41567836SJohn.Forte@Sun.COM 		}
41577836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
41587836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
41597836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
41607836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
41617836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
41627836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
41637836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_ONLINE_COMPLETE, arg);
41647836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
41657836SJohn.Forte@Sun.COM 		} else {
41667836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
41677836SJohn.Forte@Sun.COM 		}
41687836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
41697836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
41707836SJohn.Forte@Sun.COM 
41717836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE:
41727836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE) {
41737836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
41747836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41757836SJohn.Forte@Sun.COM 		}
41767836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE) {
41777836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41787836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41797836SJohn.Forte@Sun.COM 		}
41807836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_OFFLINING;
41817836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41827836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
41837836SJohn.Forte@Sun.COM 		break;
41847836SJohn.Forte@Sun.COM 
41857836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE_COMPLETE:
41867836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
41877836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41887836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41897836SJohn.Forte@Sun.COM 		}
41907836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
41917836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
41927836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
41937836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
41947836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
41957836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
41967836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_OFFLINE_COMPLETE, arg);
41977836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
41987836SJohn.Forte@Sun.COM 		} else {
41997836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
42007836SJohn.Forte@Sun.COM 		}
42017836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
42027836SJohn.Forte@Sun.COM 		break;
42037836SJohn.Forte@Sun.COM 
42047836SJohn.Forte@Sun.COM 	default:
42057836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd);
42067836SJohn.Forte@Sun.COM 		ret = STMF_INVALID_ARG;
42077836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
42087836SJohn.Forte@Sun.COM 	}
42097836SJohn.Forte@Sun.COM 
42107836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
42117836SJohn.Forte@Sun.COM 
42127836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:;
42137836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
42147836SJohn.Forte@Sun.COM 	return (ret);
42157836SJohn.Forte@Sun.COM }
42167836SJohn.Forte@Sun.COM 
42177836SJohn.Forte@Sun.COM /* ARGSUSED */
42187836SJohn.Forte@Sun.COM stmf_status_t
42197836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
42207836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
42217836SJohn.Forte@Sun.COM {
42227836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
42237836SJohn.Forte@Sun.COM }
42247836SJohn.Forte@Sun.COM 
42257836SJohn.Forte@Sun.COM /* ARGSUSED */
42267836SJohn.Forte@Sun.COM stmf_status_t
42277836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
42287836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
42297836SJohn.Forte@Sun.COM {
42307836SJohn.Forte@Sun.COM 	uint32_t cl = SI_GET_CLASS(cmd);
42317836SJohn.Forte@Sun.COM 
42327836SJohn.Forte@Sun.COM 	if (cl == SI_STMF) {
42337836SJohn.Forte@Sun.COM 		return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep));
42347836SJohn.Forte@Sun.COM 	}
42357836SJohn.Forte@Sun.COM 	if (cl == SI_LPORT) {
42368662SJordan.Vaughan@Sun.com 		return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1,
42378662SJordan.Vaughan@Sun.com 		    arg2, buf, bufsizep));
42387836SJohn.Forte@Sun.COM 	} else if (cl == SI_LU) {
42398662SJordan.Vaughan@Sun.com 		return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf,
42408662SJordan.Vaughan@Sun.com 		    bufsizep));
42417836SJohn.Forte@Sun.COM 	}
42427836SJohn.Forte@Sun.COM 
42437836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
42447836SJohn.Forte@Sun.COM }
42457836SJohn.Forte@Sun.COM 
42467836SJohn.Forte@Sun.COM /*
42479857SPeter.Cudhea@Sun.COM  * Used by port providers. pwwn is 8 byte wwn, sdid is the devid used by
42487836SJohn.Forte@Sun.COM  * stmf to register local ports. The ident should have 20 bytes in buffer
42497836SJohn.Forte@Sun.COM  * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string.
42507836SJohn.Forte@Sun.COM  */
42517836SJohn.Forte@Sun.COM void
42527836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn,
42537836SJohn.Forte@Sun.COM     uint8_t protocol_id)
42547836SJohn.Forte@Sun.COM {
42559857SPeter.Cudhea@Sun.COM 	char wwn_str[20+1];
42569857SPeter.Cudhea@Sun.COM 
42577836SJohn.Forte@Sun.COM 	sdid->protocol_id = protocol_id;
42587836SJohn.Forte@Sun.COM 	sdid->piv = 1;
42597836SJohn.Forte@Sun.COM 	sdid->code_set = CODE_SET_ASCII;
42607836SJohn.Forte@Sun.COM 	sdid->association = ID_IS_TARGET_PORT;
42617836SJohn.Forte@Sun.COM 	sdid->ident_length = 20;
42629857SPeter.Cudhea@Sun.COM 	/* Convert wwn value to "wwn.XXXXXXXXXXXXXXXX" format */
42639857SPeter.Cudhea@Sun.COM 	(void) snprintf(wwn_str, sizeof (wwn_str),
42647836SJohn.Forte@Sun.COM 	    "wwn.%02X%02X%02X%02X%02X%02X%02X%02X",
42657836SJohn.Forte@Sun.COM 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
42669857SPeter.Cudhea@Sun.COM 	bcopy(wwn_str, (char *)sdid->ident, 20);
42677836SJohn.Forte@Sun.COM }
42687836SJohn.Forte@Sun.COM 
42699857SPeter.Cudhea@Sun.COM 
42707836SJohn.Forte@Sun.COM stmf_xfer_data_t *
42717836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data()
42727836SJohn.Forte@Sun.COM {
42737836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
42747836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
42757836SJohn.Forte@Sun.COM 	uint8_t *p;
42767836SJohn.Forte@Sun.COM 	uint32_t sz, asz, nports;
42777836SJohn.Forte@Sun.COM 
42787836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
42797836SJohn.Forte@Sun.COM 	/* The spec only allows for 255 ports to be reported */
42807836SJohn.Forte@Sun.COM 	nports = min(stmf_state.stmf_nlports, 255);
42817836SJohn.Forte@Sun.COM 	sz = (nports * 4) + 12;
42827836SJohn.Forte@Sun.COM 	asz = sz + sizeof (*xd) - 4;
42837836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
42847836SJohn.Forte@Sun.COM 	if (xd == NULL) {
42857836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
42867836SJohn.Forte@Sun.COM 		return (NULL);
42877836SJohn.Forte@Sun.COM 	}
42887836SJohn.Forte@Sun.COM 	xd->alloc_size = asz;
42897836SJohn.Forte@Sun.COM 	xd->size_left = sz;
42907836SJohn.Forte@Sun.COM 
42917836SJohn.Forte@Sun.COM 	p = xd->buf;
42927836SJohn.Forte@Sun.COM 
42937836SJohn.Forte@Sun.COM 	*((uint32_t *)p) = BE_32(sz - 4);
42947836SJohn.Forte@Sun.COM 	p += 4;
42957836SJohn.Forte@Sun.COM 	p[0] = 0x80;	/* PREF */
42967836SJohn.Forte@Sun.COM 	p[1] = 1;	/* AO_SUP */
42977836SJohn.Forte@Sun.COM 	p[7] = nports & 0xff;
42987836SJohn.Forte@Sun.COM 	p += 8;
42997836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport && nports;
43007836SJohn.Forte@Sun.COM 	    nports++, ilport = ilport->ilport_next, p += 4) {
43017836SJohn.Forte@Sun.COM 		((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid);
43027836SJohn.Forte@Sun.COM 	}
43037836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
43047836SJohn.Forte@Sun.COM 
43057836SJohn.Forte@Sun.COM 	return (xd);
43067836SJohn.Forte@Sun.COM }
43077836SJohn.Forte@Sun.COM 
43089585STim.Szeto@Sun.COM struct scsi_devid_desc *
43099585STim.Szeto@Sun.COM stmf_scsilib_get_devid_desc(uint16_t rtpid)
43109585STim.Szeto@Sun.COM {
43119585STim.Szeto@Sun.COM 	scsi_devid_desc_t *devid = NULL;
43129585STim.Szeto@Sun.COM 	stmf_i_local_port_t *ilport;
43139585STim.Szeto@Sun.COM 
43149585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
43159585STim.Szeto@Sun.COM 
43169585STim.Szeto@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport;
43179585STim.Szeto@Sun.COM 	    ilport = ilport->ilport_next) {
43189585STim.Szeto@Sun.COM 		if (ilport->ilport_rtpid == rtpid) {
43199585STim.Szeto@Sun.COM 			scsi_devid_desc_t *id = ilport->ilport_lport->lport_id;
43209585STim.Szeto@Sun.COM 			uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 +
43219585STim.Szeto@Sun.COM 			    id->ident_length;
43229585STim.Szeto@Sun.COM 			devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz,
43239585STim.Szeto@Sun.COM 			    KM_NOSLEEP);
43249585STim.Szeto@Sun.COM 			if (devid != NULL) {
43259585STim.Szeto@Sun.COM 				bcopy(id, devid, id_sz);
43269585STim.Szeto@Sun.COM 			}
43279585STim.Szeto@Sun.COM 			break;
43289585STim.Szeto@Sun.COM 		}
43299585STim.Szeto@Sun.COM 	}
43309585STim.Szeto@Sun.COM 
43319585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
43329585STim.Szeto@Sun.COM 	return (devid);
43339585STim.Szeto@Sun.COM }
43349585STim.Szeto@Sun.COM 
43359585STim.Szeto@Sun.COM uint16_t
43369585STim.Szeto@Sun.COM stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid)
43379585STim.Szeto@Sun.COM {
43389585STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilport;
43399585STim.Szeto@Sun.COM 	scsi_devid_desc_t	*id;
43409585STim.Szeto@Sun.COM 	uint16_t		rtpid = 0;
43419585STim.Szeto@Sun.COM 
43429585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
43439585STim.Szeto@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport;
43449585STim.Szeto@Sun.COM 	    ilport = ilport->ilport_next) {
43459585STim.Szeto@Sun.COM 		id = ilport->ilport_lport->lport_id;
43469585STim.Szeto@Sun.COM 		if ((devid->ident_length == id->ident_length) &&
43479585STim.Szeto@Sun.COM 		    (memcmp(devid->ident, id->ident, id->ident_length) == 0)) {
43489585STim.Szeto@Sun.COM 			rtpid = ilport->ilport_rtpid;
43499585STim.Szeto@Sun.COM 			break;
43509585STim.Szeto@Sun.COM 		}
43519585STim.Szeto@Sun.COM 	}
43529585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
43539585STim.Szeto@Sun.COM 	return (rtpid);
43549585STim.Szeto@Sun.COM }
43557836SJohn.Forte@Sun.COM 
43567836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0;
43577836SJohn.Forte@Sun.COM 
43587836SJohn.Forte@Sun.COM stmf_status_t
43597836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id)
43607836SJohn.Forte@Sun.COM {
43617836SJohn.Forte@Sun.COM 	uint8_t *p;
43627836SJohn.Forte@Sun.COM 	struct timeval32 timestamp32;
43637836SJohn.Forte@Sun.COM 	uint32_t *t = (uint32_t *)&timestamp32;
43647836SJohn.Forte@Sun.COM 	struct ether_addr mac;
43657836SJohn.Forte@Sun.COM 	uint8_t *e = (uint8_t *)&mac;
43667836SJohn.Forte@Sun.COM 
43677836SJohn.Forte@Sun.COM 	if (company_id == COMPANY_ID_NONE)
43687836SJohn.Forte@Sun.COM 		company_id = COMPANY_ID_SUN;
43697836SJohn.Forte@Sun.COM 
43707836SJohn.Forte@Sun.COM 	if (lu_id->ident_length != 0x10)
43717836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
43727836SJohn.Forte@Sun.COM 
43737836SJohn.Forte@Sun.COM 	p = (uint8_t *)lu_id;
43747836SJohn.Forte@Sun.COM 
43757836SJohn.Forte@Sun.COM 	atomic_add_16(&stmf_lu_id_gen_number, 1);
43767836SJohn.Forte@Sun.COM 
43777836SJohn.Forte@Sun.COM 	p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
43787836SJohn.Forte@Sun.COM 	p[4] = ((company_id >> 20) & 0xf) | 0x60;
43797836SJohn.Forte@Sun.COM 	p[5] = (company_id >> 12) & 0xff;
43807836SJohn.Forte@Sun.COM 	p[6] = (company_id >> 4) & 0xff;
43817836SJohn.Forte@Sun.COM 	p[7] = (company_id << 4) & 0xf0;
43827836SJohn.Forte@Sun.COM 	if (!localetheraddr((struct ether_addr *)NULL, &mac)) {
43838662SJordan.Vaughan@Sun.com 		int hid = BE_32((int)zone_get_hostid(NULL));
43847836SJohn.Forte@Sun.COM 		e[0] = (hid >> 24) & 0xff;
43857836SJohn.Forte@Sun.COM 		e[1] = (hid >> 16) & 0xff;
43867836SJohn.Forte@Sun.COM 		e[2] = (hid >> 8) & 0xff;
43877836SJohn.Forte@Sun.COM 		e[3] = hid & 0xff;
43887836SJohn.Forte@Sun.COM 		e[4] = e[5] = 0;
43897836SJohn.Forte@Sun.COM 	}
43907836SJohn.Forte@Sun.COM 	bcopy(e, p+8, 6);
43917836SJohn.Forte@Sun.COM 	uniqtime32(&timestamp32);
43927836SJohn.Forte@Sun.COM 	*t = BE_32(*t);
43937836SJohn.Forte@Sun.COM 	bcopy(t, p+14, 4);
43947836SJohn.Forte@Sun.COM 	p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
43957836SJohn.Forte@Sun.COM 	p[19] = stmf_lu_id_gen_number & 0xff;
43967836SJohn.Forte@Sun.COM 
43977836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
43987836SJohn.Forte@Sun.COM }
43997836SJohn.Forte@Sun.COM 
44007836SJohn.Forte@Sun.COM /*
44017836SJohn.Forte@Sun.COM  * saa is sense key, ASC, ASCQ
44027836SJohn.Forte@Sun.COM  */
44037836SJohn.Forte@Sun.COM void
44047836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa)
44057836SJohn.Forte@Sun.COM {
44067836SJohn.Forte@Sun.COM 	uint8_t sd[18];
44077836SJohn.Forte@Sun.COM 	task->task_scsi_status = st;
44087836SJohn.Forte@Sun.COM 	if (st == 2) {
44097836SJohn.Forte@Sun.COM 		bzero(sd, 18);
44107836SJohn.Forte@Sun.COM 		sd[0] = 0x70;
44117836SJohn.Forte@Sun.COM 		sd[2] = (saa >> 16) & 0xf;
44127836SJohn.Forte@Sun.COM 		sd[7] = 10;
44137836SJohn.Forte@Sun.COM 		sd[12] = (saa >> 8) & 0xff;
44147836SJohn.Forte@Sun.COM 		sd[13] = saa & 0xff;
44157836SJohn.Forte@Sun.COM 		task->task_sense_data = sd;
44167836SJohn.Forte@Sun.COM 		task->task_sense_length = 18;
44177836SJohn.Forte@Sun.COM 	} else {
44187836SJohn.Forte@Sun.COM 		task->task_sense_data = NULL;
44197836SJohn.Forte@Sun.COM 		task->task_sense_length = 0;
44207836SJohn.Forte@Sun.COM 	}
44217836SJohn.Forte@Sun.COM 	(void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
44227836SJohn.Forte@Sun.COM }
44237836SJohn.Forte@Sun.COM 
44247836SJohn.Forte@Sun.COM uint32_t
44257836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page,
44267836SJohn.Forte@Sun.COM     uint32_t page_len, uint8_t byte0, uint32_t vpd_mask)
44277836SJohn.Forte@Sun.COM {
44287836SJohn.Forte@Sun.COM 	uint8_t		*p = NULL;
44297836SJohn.Forte@Sun.COM 	uint8_t		small_buf[32];
44307836SJohn.Forte@Sun.COM 	uint32_t	sz = 0;
44317836SJohn.Forte@Sun.COM 	uint32_t	n = 4;
44327836SJohn.Forte@Sun.COM 	uint32_t	m = 0;
44337836SJohn.Forte@Sun.COM 	uint32_t	last_bit = 0;
44347836SJohn.Forte@Sun.COM 
44357836SJohn.Forte@Sun.COM 	if (page_len < 4)
44367836SJohn.Forte@Sun.COM 		return (0);
44377836SJohn.Forte@Sun.COM 	if (page_len > 65535)
44387836SJohn.Forte@Sun.COM 		page_len = 65535;
44397836SJohn.Forte@Sun.COM 
44407836SJohn.Forte@Sun.COM 	page[0] = byte0;
44417836SJohn.Forte@Sun.COM 	page[1] = 0x83;
44427836SJohn.Forte@Sun.COM 
44437836SJohn.Forte@Sun.COM 	/* CONSTCOND */
44447836SJohn.Forte@Sun.COM 	while (1) {
44457836SJohn.Forte@Sun.COM 		m += sz;
44467836SJohn.Forte@Sun.COM 		if (sz && (page_len > n)) {
44477836SJohn.Forte@Sun.COM 			uint32_t copysz;
44487836SJohn.Forte@Sun.COM 			copysz = page_len > (n + sz) ? sz : page_len - n;
44497836SJohn.Forte@Sun.COM 			bcopy(p, page + n, copysz);
44507836SJohn.Forte@Sun.COM 			n += copysz;
44517836SJohn.Forte@Sun.COM 		}
44527836SJohn.Forte@Sun.COM 		vpd_mask &= ~last_bit;
44537836SJohn.Forte@Sun.COM 		if (vpd_mask == 0)
44547836SJohn.Forte@Sun.COM 			break;
44557836SJohn.Forte@Sun.COM 
44567836SJohn.Forte@Sun.COM 		if (vpd_mask & STMF_VPD_LU_ID) {
44577836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_LU_ID;
44587836SJohn.Forte@Sun.COM 			sz = task->task_lu->lu_id->ident_length + 4;
44597836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lu->lu_id;
44607836SJohn.Forte@Sun.COM 			continue;
44617836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TARGET_ID) {
44627836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TARGET_ID;
44637836SJohn.Forte@Sun.COM 			sz = task->task_lport->lport_id->ident_length + 4;
44647836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lport->lport_id;
44657836SJohn.Forte@Sun.COM 			continue;
44667836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TP_GROUP) {
44677836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TP_GROUP;
44687836SJohn.Forte@Sun.COM 			p = small_buf;
44697836SJohn.Forte@Sun.COM 			bzero(p, 8);
44707836SJohn.Forte@Sun.COM 			p[0] = 1;
44717836SJohn.Forte@Sun.COM 			p[1] = 0x15;
44727836SJohn.Forte@Sun.COM 			p[3] = 4;
44737836SJohn.Forte@Sun.COM 			/* Group ID is always 0 */
44747836SJohn.Forte@Sun.COM 			sz = 8;
44757836SJohn.Forte@Sun.COM 			continue;
44767836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) {
44777836SJohn.Forte@Sun.COM 			stmf_i_local_port_t *ilport;
44787836SJohn.Forte@Sun.COM 
44797836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_RELATIVE_TP_ID;
44807836SJohn.Forte@Sun.COM 			p = small_buf;
44817836SJohn.Forte@Sun.COM 			bzero(p, 8);
44827836SJohn.Forte@Sun.COM 			p[0] = 1;
44837836SJohn.Forte@Sun.COM 			p[1] = 0x14;
44847836SJohn.Forte@Sun.COM 			p[3] = 4;
44857836SJohn.Forte@Sun.COM 			ilport = (stmf_i_local_port_t *)
44868662SJordan.Vaughan@Sun.com 			    task->task_lport->lport_stmf_private;
44877836SJohn.Forte@Sun.COM 			p[6] = (ilport->ilport_rtpid >> 8) & 0xff;
44887836SJohn.Forte@Sun.COM 			p[7] = ilport->ilport_rtpid & 0xff;
44897836SJohn.Forte@Sun.COM 			sz = 8;
44907836SJohn.Forte@Sun.COM 			continue;
44917836SJohn.Forte@Sun.COM 		} else {
44927836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "Invalid vpd_mask");
44937836SJohn.Forte@Sun.COM 			break;
44947836SJohn.Forte@Sun.COM 		}
44957836SJohn.Forte@Sun.COM 	}
44967836SJohn.Forte@Sun.COM 
44977836SJohn.Forte@Sun.COM 	page[2] = (m >> 8) & 0xff;
44987836SJohn.Forte@Sun.COM 	page[3] = m & 0xff;
44997836SJohn.Forte@Sun.COM 
45007836SJohn.Forte@Sun.COM 	return (n);
45017836SJohn.Forte@Sun.COM }
45027836SJohn.Forte@Sun.COM 
45037836SJohn.Forte@Sun.COM void
45047836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf)
45057836SJohn.Forte@Sun.COM {
45067836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
45078662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
45087836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
45097836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
45107836SJohn.Forte@Sun.COM 
45117836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING;
45127836SJohn.Forte@Sun.COM 	task->task_cmd_xfer_length =
45137836SJohn.Forte@Sun.COM 	    ((((uint32_t)task->task_cdb[6]) << 24) |
45147836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[7]) << 16) |
45157836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[8]) << 8) |
45167836SJohn.Forte@Sun.COM 	    ((uint32_t)task->task_cdb[9]));
45177836SJohn.Forte@Sun.COM 
45187836SJohn.Forte@Sun.COM 	if (task->task_additional_flags &
45197836SJohn.Forte@Sun.COM 	    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
45207836SJohn.Forte@Sun.COM 		task->task_expected_xfer_length =
45217836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length;
45227836SJohn.Forte@Sun.COM 	}
45237836SJohn.Forte@Sun.COM 
4524*9962SWayne.Ihde@Sun.COM 	if (task->task_cmd_xfer_length == 0) {
4525*9962SWayne.Ihde@Sun.COM 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
4526*9962SWayne.Ihde@Sun.COM 		return;
4527*9962SWayne.Ihde@Sun.COM 	}
4528*9962SWayne.Ihde@Sun.COM 	if (task->task_cmd_xfer_length < 4) {
45297836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
45308662SJordan.Vaughan@Sun.com 		    STMF_SAA_INVALID_FIELD_IN_CDB);
45317836SJohn.Forte@Sun.COM 		return;
45327836SJohn.Forte@Sun.COM 	}
45337836SJohn.Forte@Sun.COM 
45347836SJohn.Forte@Sun.COM 	sz = min(task->task_expected_xfer_length,
45357836SJohn.Forte@Sun.COM 	    task->task_cmd_xfer_length);
45367836SJohn.Forte@Sun.COM 
45377836SJohn.Forte@Sun.COM 	xd = stmf_prepare_tpgs_data();
45387836SJohn.Forte@Sun.COM 
45397836SJohn.Forte@Sun.COM 	if (xd == NULL) {
45407836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
45417836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
45427836SJohn.Forte@Sun.COM 		return;
45437836SJohn.Forte@Sun.COM 	}
45447836SJohn.Forte@Sun.COM 
45457836SJohn.Forte@Sun.COM 	sz = min(sz, xd->size_left);
45467836SJohn.Forte@Sun.COM 	xd->size_left = sz;
45477836SJohn.Forte@Sun.COM 	minsz = min(512, sz);
45487836SJohn.Forte@Sun.COM 
45497836SJohn.Forte@Sun.COM 	if (dbuf == NULL)
45507836SJohn.Forte@Sun.COM 		dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
45517836SJohn.Forte@Sun.COM 	if (dbuf == NULL) {
45527836SJohn.Forte@Sun.COM 		kmem_free(xd, xd->alloc_size);
45537836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
45547836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
45557836SJohn.Forte@Sun.COM 		return;
45567836SJohn.Forte@Sun.COM 	}
45577836SJohn.Forte@Sun.COM 	dbuf->db_lu_private = xd;
45587836SJohn.Forte@Sun.COM 	stmf_xd_to_dbuf(dbuf);
45597836SJohn.Forte@Sun.COM 
45607836SJohn.Forte@Sun.COM 	dbuf->db_flags = DB_DIRECTION_TO_RPORT;
45617836SJohn.Forte@Sun.COM 	(void) stmf_xfer_data(task, dbuf, 0);
45627836SJohn.Forte@Sun.COM 
45637836SJohn.Forte@Sun.COM }
45647836SJohn.Forte@Sun.COM 
45657836SJohn.Forte@Sun.COM void
45667836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task)
45677836SJohn.Forte@Sun.COM {
45687836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
45697836SJohn.Forte@Sun.COM 	/*
45707836SJohn.Forte@Sun.COM 	 * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET
45717836SJohn.Forte@Sun.COM 	 * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state
45727836SJohn.Forte@Sun.COM 	 * in these cases. This needs to be changed to abort only the required
45737836SJohn.Forte@Sun.COM 	 * set.
45747836SJohn.Forte@Sun.COM 	 */
45757836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
45767836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
45777836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
45787836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
45797836SJohn.Forte@Sun.COM 		stmf_handle_lun_reset(task);
45807836SJohn.Forte@Sun.COM 		return;
45817836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
45827836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
45837836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
45847836SJohn.Forte@Sun.COM 		stmf_handle_target_reset(task);
45857836SJohn.Forte@Sun.COM 		return;
45867836SJohn.Forte@Sun.COM 	default:
45877836SJohn.Forte@Sun.COM 		/* We dont support this task mgmt function */
45887836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
45897836SJohn.Forte@Sun.COM 		    STMF_SAA_INVALID_FIELD_IN_CMD_IU);
45907836SJohn.Forte@Sun.COM 		return;
45917836SJohn.Forte@Sun.COM 	}
45927836SJohn.Forte@Sun.COM }
45937836SJohn.Forte@Sun.COM 
45947836SJohn.Forte@Sun.COM void
45957836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task)
45967836SJohn.Forte@Sun.COM {
45977836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
45987836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
45997836SJohn.Forte@Sun.COM 
46007836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
46017836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
46027836SJohn.Forte@Sun.COM 
46037836SJohn.Forte@Sun.COM 	/*
46047836SJohn.Forte@Sun.COM 	 * To sync with target reset, grab this lock. The LU is not going
46057836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
46067836SJohn.Forte@Sun.COM 	 */
46077836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
46087836SJohn.Forte@Sun.COM 
46097836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
46107836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
46117836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
46128662SJordan.Vaughan@Sun.com 		    STMF_SAA_OPERATION_IN_PROGRESS);
46137836SJohn.Forte@Sun.COM 		return;
46147836SJohn.Forte@Sun.COM 	}
46157836SJohn.Forte@Sun.COM 	atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
46167836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
46177836SJohn.Forte@Sun.COM 
46187836SJohn.Forte@Sun.COM 	/*
46197836SJohn.Forte@Sun.COM 	 * Mark this task as the one causing LU reset so that we know who
46207836SJohn.Forte@Sun.COM 	 * was responsible for setting the ILU_RESET_ACTIVE. In case this
46217836SJohn.Forte@Sun.COM 	 * task itself gets aborted, we will clear ILU_RESET_ACTIVE.
46227836SJohn.Forte@Sun.COM 	 */
46237836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET;
46247836SJohn.Forte@Sun.COM 
46257836SJohn.Forte@Sun.COM 	/* Initiatiate abort on all commands on this LU except this one */
46267836SJohn.Forte@Sun.COM 	stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu);
46277836SJohn.Forte@Sun.COM 
46287836SJohn.Forte@Sun.COM 	/* Start polling on this task */
46297836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
46307836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
46317836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
46328662SJordan.Vaughan@Sun.com 		    NULL);
46337836SJohn.Forte@Sun.COM 		return;
46347836SJohn.Forte@Sun.COM 	}
46357836SJohn.Forte@Sun.COM }
46367836SJohn.Forte@Sun.COM 
46377836SJohn.Forte@Sun.COM void
46387836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task)
46397836SJohn.Forte@Sun.COM {
46407836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
46417836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
46427836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
46437836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
46447836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
46457836SJohn.Forte@Sun.COM 	int i, lf;
46467836SJohn.Forte@Sun.COM 
46477836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
46487836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private;
46497836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
46507836SJohn.Forte@Sun.COM 
46517836SJohn.Forte@Sun.COM 	/*
46527836SJohn.Forte@Sun.COM 	 * To sync with LUN reset, grab this lock. The session is not going
46537836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
46547836SJohn.Forte@Sun.COM 	 */
46557836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
46567979SSumit.Gupta@Sun.COM 
46577979SSumit.Gupta@Sun.COM 	/* Grab the session lock as a writer to prevent any changes in it */
46587979SSumit.Gupta@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
46597979SSumit.Gupta@Sun.COM 
46607836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_RESET_ACTIVE) {
46617979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
46627836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
46637836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
46648662SJordan.Vaughan@Sun.com 		    STMF_SAA_OPERATION_IN_PROGRESS);
46657836SJohn.Forte@Sun.COM 		return;
46667836SJohn.Forte@Sun.COM 	}
46677836SJohn.Forte@Sun.COM 	atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE);
46687836SJohn.Forte@Sun.COM 
46697836SJohn.Forte@Sun.COM 	/*
46707836SJohn.Forte@Sun.COM 	 * Now go through each LUN in this session and make sure all of them
46717836SJohn.Forte@Sun.COM 	 * can be reset.
46727836SJohn.Forte@Sun.COM 	 */
46737836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
46747836SJohn.Forte@Sun.COM 	for (i = 0, lf = 0; i < lm->lm_nentries; i++) {
46757836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
46767836SJohn.Forte@Sun.COM 			continue;
46777836SJohn.Forte@Sun.COM 		lf++;
46787836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
46797836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
46807836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
46817836SJohn.Forte@Sun.COM 			atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
46827979SSumit.Gupta@Sun.COM 			rw_exit(iss->iss_lockp);
46837836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
46847836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
46858662SJordan.Vaughan@Sun.com 			    STMF_SAA_OPERATION_IN_PROGRESS);
46867836SJohn.Forte@Sun.COM 			return;
46877836SJohn.Forte@Sun.COM 		}
46887836SJohn.Forte@Sun.COM 	}
46897836SJohn.Forte@Sun.COM 	if (lf == 0) {
46907836SJohn.Forte@Sun.COM 		/* No luns in this session */
46917836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
46927979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
46937836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
46947836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
46957836SJohn.Forte@Sun.COM 		return;
46967836SJohn.Forte@Sun.COM 	}
46977836SJohn.Forte@Sun.COM 
46987836SJohn.Forte@Sun.COM 	/* ok, start the damage */
46997836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING |
47008662SJordan.Vaughan@Sun.com 	    ITASK_CAUSING_TARGET_RESET;
47017836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
47027836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
47037836SJohn.Forte@Sun.COM 			continue;
47047836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
47057836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
47067836SJohn.Forte@Sun.COM 		atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
47077836SJohn.Forte@Sun.COM 	}
47087979SSumit.Gupta@Sun.COM 	rw_exit(iss->iss_lockp);
47097836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
47107836SJohn.Forte@Sun.COM 
47117836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
47127836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
47137836SJohn.Forte@Sun.COM 			continue;
47147836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
47157836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
47168662SJordan.Vaughan@Sun.com 		    lm_ent->ent_lu);
47177836SJohn.Forte@Sun.COM 	}
47187836SJohn.Forte@Sun.COM 
47197836SJohn.Forte@Sun.COM 	/* Start polling on this task */
47207836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
47217836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
47227836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
47238662SJordan.Vaughan@Sun.com 		    NULL);
47247836SJohn.Forte@Sun.COM 		return;
47257836SJohn.Forte@Sun.COM 	}
47267836SJohn.Forte@Sun.COM }
47277836SJohn.Forte@Sun.COM 
47287836SJohn.Forte@Sun.COM int
47297836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask)
47307836SJohn.Forte@Sun.COM {
47317836SJohn.Forte@Sun.COM 	scsi_task_t *task = itask->itask_task;
47327836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
47337836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
47347836SJohn.Forte@Sun.COM 
47357836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
47367836SJohn.Forte@Sun.COM 	if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) ||
47377836SJohn.Forte@Sun.COM 	    (task->task_cdb[0] == SCMD_INQUIRY)) {
47387836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
47397836SJohn.Forte@Sun.COM 		return (0);
47407836SJohn.Forte@Sun.COM 	}
47417836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
47428662SJordan.Vaughan@Sun.com 	    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
47437836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
47447836SJohn.Forte@Sun.COM 
47457836SJohn.Forte@Sun.COM 	if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
47467836SJohn.Forte@Sun.COM 		return (0);
47477836SJohn.Forte@Sun.COM 	}
47487836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK,
47497836SJohn.Forte@Sun.COM 	    STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED);
47507836SJohn.Forte@Sun.COM 	return (1);
47517836SJohn.Forte@Sun.COM }
47527836SJohn.Forte@Sun.COM 
47537836SJohn.Forte@Sun.COM void
47547836SJohn.Forte@Sun.COM stmf_worker_init()
47557836SJohn.Forte@Sun.COM {
47567836SJohn.Forte@Sun.COM 	uint32_t i;
47577836SJohn.Forte@Sun.COM 
47587836SJohn.Forte@Sun.COM 	/* Make local copy of global tunables */
47597836SJohn.Forte@Sun.COM 	stmf_i_max_nworkers = stmf_max_nworkers;
47607836SJohn.Forte@Sun.COM 	stmf_i_min_nworkers = stmf_min_nworkers;
47617836SJohn.Forte@Sun.COM 
47627836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers == NULL);
47637836SJohn.Forte@Sun.COM 	if (stmf_i_min_nworkers < 4) {
47647836SJohn.Forte@Sun.COM 		stmf_i_min_nworkers = 4;
47657836SJohn.Forte@Sun.COM 	}
47667836SJohn.Forte@Sun.COM 	if (stmf_i_max_nworkers < stmf_i_min_nworkers) {
47677836SJohn.Forte@Sun.COM 		stmf_i_max_nworkers = stmf_i_min_nworkers;
47687836SJohn.Forte@Sun.COM 	}
47697836SJohn.Forte@Sun.COM 	stmf_workers = (stmf_worker_t *)kmem_zalloc(
47707836SJohn.Forte@Sun.COM 	    sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP);
47717836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
47727836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
47737836SJohn.Forte@Sun.COM 		mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
47747836SJohn.Forte@Sun.COM 		cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
47757836SJohn.Forte@Sun.COM 	}
47767836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
47777836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_ENABLED;
47787836SJohn.Forte@Sun.COM 
47797836SJohn.Forte@Sun.COM 	/* Workers will be started by stmf_worker_mgmt() */
47807836SJohn.Forte@Sun.COM 
47817836SJohn.Forte@Sun.COM 	/* Lets wait for atleast one worker to start */
47827836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur == 0)
47837836SJohn.Forte@Sun.COM 		delay(drv_usectohz(20 * 1000));
47847836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000);
47857836SJohn.Forte@Sun.COM }
47867836SJohn.Forte@Sun.COM 
47877836SJohn.Forte@Sun.COM stmf_status_t
47887836SJohn.Forte@Sun.COM stmf_worker_fini()
47897836SJohn.Forte@Sun.COM {
47907836SJohn.Forte@Sun.COM 	int i;
47917836SJohn.Forte@Sun.COM 	clock_t sb;
47927836SJohn.Forte@Sun.COM 
47937836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED)
47947836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
47957836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers);
47967836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_DISABLED;
47977836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
47987836SJohn.Forte@Sun.COM 	cv_signal(&stmf_state.stmf_cv);
47997836SJohn.Forte@Sun.COM 
48007836SJohn.Forte@Sun.COM 	sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000);
48017836SJohn.Forte@Sun.COM 	/* Wait for all the threads to die */
48027836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur != 0) {
48037836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > sb) {
48047836SJohn.Forte@Sun.COM 			stmf_workers_state = STMF_WORKERS_ENABLED;
48057836SJohn.Forte@Sun.COM 			return (STMF_BUSY);
48067836SJohn.Forte@Sun.COM 		}
48077836SJohn.Forte@Sun.COM 		delay(drv_usectohz(100 * 1000));
48087836SJohn.Forte@Sun.COM 	}
48097836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
48107836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
48117836SJohn.Forte@Sun.COM 		mutex_destroy(&w->worker_lock);
48127836SJohn.Forte@Sun.COM 		cv_destroy(&w->worker_cv);
48137836SJohn.Forte@Sun.COM 	}
48147836SJohn.Forte@Sun.COM 	kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers);
48157836SJohn.Forte@Sun.COM 	stmf_workers = NULL;
48167836SJohn.Forte@Sun.COM 
48177836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
48187836SJohn.Forte@Sun.COM }
48197836SJohn.Forte@Sun.COM 
48207836SJohn.Forte@Sun.COM void
48217836SJohn.Forte@Sun.COM stmf_worker_task(void *arg)
48227836SJohn.Forte@Sun.COM {
48237836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
48247836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
48257836SJohn.Forte@Sun.COM 	scsi_task_t *task;
48267836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
48277836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
48287836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
48297836SJohn.Forte@Sun.COM 	clock_t wait_timer = 0;
48307836SJohn.Forte@Sun.COM 	clock_t wait_ticks;
48317836SJohn.Forte@Sun.COM 	uint32_t old, new;
48327836SJohn.Forte@Sun.COM 	uint8_t curcmd;
48337836SJohn.Forte@Sun.COM 	uint8_t abort_free;
48347836SJohn.Forte@Sun.COM 	uint8_t wait_queue;
48357836SJohn.Forte@Sun.COM 	uint8_t dec_qdepth;
48367836SJohn.Forte@Sun.COM 
48377836SJohn.Forte@Sun.COM 	w = (stmf_worker_t *)arg;
48387836SJohn.Forte@Sun.COM 	wait_ticks = drv_usectohz(10000);
48397836SJohn.Forte@Sun.COM 
48407836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
48417836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE;
48427836SJohn.Forte@Sun.COM stmf_worker_loop:;
48437836SJohn.Forte@Sun.COM 	if ((w->worker_ref_count == 0) &&
48447836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
48457836SJohn.Forte@Sun.COM 		w->worker_flags &= ~(STMF_WORKER_STARTED |
48467836SJohn.Forte@Sun.COM 		    STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE);
48477836SJohn.Forte@Sun.COM 		w->worker_tid = NULL;
48487836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
48497836SJohn.Forte@Sun.COM 		thread_exit();
48507836SJohn.Forte@Sun.COM 	}
48517836SJohn.Forte@Sun.COM 	/* CONSTCOND */
48527836SJohn.Forte@Sun.COM 	while (1) {
48537836SJohn.Forte@Sun.COM 		dec_qdepth = 0;
48547836SJohn.Forte@Sun.COM 		if (wait_timer && (ddi_get_lbolt() >= wait_timer)) {
48557836SJohn.Forte@Sun.COM 			wait_timer = 0;
48567979SSumit.Gupta@Sun.COM 			if (w->worker_wait_head) {
48577979SSumit.Gupta@Sun.COM 				ASSERT(w->worker_wait_tail);
48587979SSumit.Gupta@Sun.COM 				if (w->worker_task_head == NULL)
48597979SSumit.Gupta@Sun.COM 					w->worker_task_head =
48607979SSumit.Gupta@Sun.COM 					    w->worker_wait_head;
48617979SSumit.Gupta@Sun.COM 				else
48627979SSumit.Gupta@Sun.COM 					w->worker_task_tail->itask_worker_next =
48638662SJordan.Vaughan@Sun.com 					    w->worker_wait_head;
48647979SSumit.Gupta@Sun.COM 				w->worker_task_tail = w->worker_wait_tail;
48657979SSumit.Gupta@Sun.COM 				w->worker_wait_head = w->worker_wait_tail =
48667979SSumit.Gupta@Sun.COM 				    NULL;
48677979SSumit.Gupta@Sun.COM 			}
48687836SJohn.Forte@Sun.COM 		}
48697836SJohn.Forte@Sun.COM 		if ((itask = w->worker_task_head) == NULL) {
48707836SJohn.Forte@Sun.COM 			break;
48717836SJohn.Forte@Sun.COM 		}
48727836SJohn.Forte@Sun.COM 		task = itask->itask_task;
48737836SJohn.Forte@Sun.COM 		w->worker_task_head = itask->itask_worker_next;
48747836SJohn.Forte@Sun.COM 		if (w->worker_task_head == NULL)
48757836SJohn.Forte@Sun.COM 			w->worker_task_tail = NULL;
48767836SJohn.Forte@Sun.COM 
48777836SJohn.Forte@Sun.COM 		wait_queue = 0;
48787836SJohn.Forte@Sun.COM 		abort_free = 0;
48797836SJohn.Forte@Sun.COM 		if (itask->itask_ncmds > 0) {
48807836SJohn.Forte@Sun.COM 			curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1];
48817836SJohn.Forte@Sun.COM 		} else {
48827836SJohn.Forte@Sun.COM 			ASSERT(itask->itask_flags & ITASK_BEING_ABORTED);
48837836SJohn.Forte@Sun.COM 		}
48847836SJohn.Forte@Sun.COM 		do {
48857836SJohn.Forte@Sun.COM 			old = itask->itask_flags;
48867836SJohn.Forte@Sun.COM 			if (old & ITASK_BEING_ABORTED) {
48877836SJohn.Forte@Sun.COM 				itask->itask_ncmds = 1;
48887836SJohn.Forte@Sun.COM 				curcmd = itask->itask_cmd_stack[0] =
48897836SJohn.Forte@Sun.COM 				    ITASK_CMD_ABORT;
48907836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
48917836SJohn.Forte@Sun.COM 			} else if ((curcmd & ITASK_CMD_MASK) ==
48927836SJohn.Forte@Sun.COM 			    ITASK_CMD_NEW_TASK) {
48937836SJohn.Forte@Sun.COM 				new = old | ITASK_KNOWN_TO_LU;
48947836SJohn.Forte@Sun.COM 			} else {
48957836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
48967836SJohn.Forte@Sun.COM 			}
48977836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
48987836SJohn.Forte@Sun.COM 
48997836SJohn.Forte@Sun.COM out_itask_flag_loop:
49007836SJohn.Forte@Sun.COM 
49017836SJohn.Forte@Sun.COM 		/*
49027836SJohn.Forte@Sun.COM 		 * Decide if this task needs to go to a queue and/or if
49037836SJohn.Forte@Sun.COM 		 * we can decrement the itask_cmd_stack.
49047836SJohn.Forte@Sun.COM 		 */
49057836SJohn.Forte@Sun.COM 		if (curcmd == ITASK_CMD_ABORT) {
49067836SJohn.Forte@Sun.COM 			if (itask->itask_flags & (ITASK_KNOWN_TO_LU |
49077836SJohn.Forte@Sun.COM 			    ITASK_KNOWN_TO_TGT_PORT)) {
49087836SJohn.Forte@Sun.COM 				wait_queue = 1;
49097836SJohn.Forte@Sun.COM 			} else {
49107836SJohn.Forte@Sun.COM 				abort_free = 1;
49117836SJohn.Forte@Sun.COM 			}
49127836SJohn.Forte@Sun.COM 		} else if ((curcmd & ITASK_CMD_POLL) &&
49137836SJohn.Forte@Sun.COM 		    (itask->itask_poll_timeout > ddi_get_lbolt())) {
49147836SJohn.Forte@Sun.COM 			wait_queue = 1;
49157836SJohn.Forte@Sun.COM 		}
49167836SJohn.Forte@Sun.COM 
49177836SJohn.Forte@Sun.COM 		if (wait_queue) {
49187836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
49197836SJohn.Forte@Sun.COM 			if (w->worker_wait_tail) {
49207836SJohn.Forte@Sun.COM 				w->worker_wait_tail->itask_worker_next = itask;
49217836SJohn.Forte@Sun.COM 			} else {
49227836SJohn.Forte@Sun.COM 				w->worker_wait_head = itask;
49237836SJohn.Forte@Sun.COM 			}
49247836SJohn.Forte@Sun.COM 			w->worker_wait_tail = itask;
49257836SJohn.Forte@Sun.COM 			if (wait_timer == 0) {
49267836SJohn.Forte@Sun.COM 				wait_timer = ddi_get_lbolt() + wait_ticks;
49277836SJohn.Forte@Sun.COM 			}
49287836SJohn.Forte@Sun.COM 		} else if ((--(itask->itask_ncmds)) != 0) {
49297836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
49307836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
49317836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
49327836SJohn.Forte@Sun.COM 			} else {
49337836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
49347836SJohn.Forte@Sun.COM 			}
49357836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
49367836SJohn.Forte@Sun.COM 		} else {
49377836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
49387836SJohn.Forte@Sun.COM 			    ~ITASK_IN_WORKER_QUEUE);
49397836SJohn.Forte@Sun.COM 			/*
49407836SJohn.Forte@Sun.COM 			 * This is where the queue depth should go down by
49417836SJohn.Forte@Sun.COM 			 * one but we delay that on purpose to account for
49427836SJohn.Forte@Sun.COM 			 * the call into the provider. The actual decrement
49437836SJohn.Forte@Sun.COM 			 * happens after the worker has done its job.
49447836SJohn.Forte@Sun.COM 			 */
49457836SJohn.Forte@Sun.COM 			dec_qdepth = 1;
49467836SJohn.Forte@Sun.COM 		}
49477836SJohn.Forte@Sun.COM 
49487836SJohn.Forte@Sun.COM 		/* We made it here means we are going to call LU */
49497836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0)
49507836SJohn.Forte@Sun.COM 			lu = task->task_lu;
49517836SJohn.Forte@Sun.COM 		else
49527836SJohn.Forte@Sun.COM 			lu = dlun0;
49537836SJohn.Forte@Sun.COM 		dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)];
49547836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
49557836SJohn.Forte@Sun.COM 		curcmd &= ITASK_CMD_MASK;
49567836SJohn.Forte@Sun.COM 		switch (curcmd) {
49577836SJohn.Forte@Sun.COM 		case ITASK_CMD_NEW_TASK:
49587836SJohn.Forte@Sun.COM 			iss = (stmf_i_scsi_session_t *)
49597836SJohn.Forte@Sun.COM 			    task->task_session->ss_stmf_private;
49609435STim.Szeto@Sun.COM 			stmf_update_kstat_lu_q(task, kstat_waitq_to_runq);
49619435STim.Szeto@Sun.COM 			stmf_update_kstat_lport_q(task, kstat_waitq_to_runq);
49627836SJohn.Forte@Sun.COM 			if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) {
49637836SJohn.Forte@Sun.COM 				if (stmf_handle_cmd_during_ic(itask))
49647836SJohn.Forte@Sun.COM 					break;
49657836SJohn.Forte@Sun.COM 			}
49667836SJohn.Forte@Sun.COM #ifdef	DEBUG
49677836SJohn.Forte@Sun.COM 			if (stmf_drop_task_counter > 0) {
49687836SJohn.Forte@Sun.COM 				if (atomic_add_32_nv(
49697836SJohn.Forte@Sun.COM 				    (uint32_t *)&stmf_drop_task_counter,
49707836SJohn.Forte@Sun.COM 				    -1) == 1) {
49717836SJohn.Forte@Sun.COM 					break;
49727836SJohn.Forte@Sun.COM 				}
49737836SJohn.Forte@Sun.COM 			}
49747836SJohn.Forte@Sun.COM #endif
49758859STim.Szeto@Sun.COM 			DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task);
49767836SJohn.Forte@Sun.COM 			lu->lu_new_task(task, dbuf);
49777836SJohn.Forte@Sun.COM 			break;
49787836SJohn.Forte@Sun.COM 		case ITASK_CMD_DATA_XFER_DONE:
49797836SJohn.Forte@Sun.COM 			lu->lu_dbuf_xfer_done(task, dbuf);
49807836SJohn.Forte@Sun.COM 			break;
49817836SJohn.Forte@Sun.COM 		case ITASK_CMD_STATUS_DONE:
49827836SJohn.Forte@Sun.COM 			lu->lu_send_status_done(task);
49837836SJohn.Forte@Sun.COM 			break;
49847836SJohn.Forte@Sun.COM 		case ITASK_CMD_ABORT:
49857836SJohn.Forte@Sun.COM 			if (abort_free) {
49867836SJohn.Forte@Sun.COM 				stmf_task_free(task);
49877836SJohn.Forte@Sun.COM 			} else {
49887836SJohn.Forte@Sun.COM 				stmf_do_task_abort(task);
49897836SJohn.Forte@Sun.COM 			}
49907836SJohn.Forte@Sun.COM 			break;
49917836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LU:
49927836SJohn.Forte@Sun.COM 			if (!wait_queue) {
49937836SJohn.Forte@Sun.COM 				lu->lu_task_poll(task);
49947836SJohn.Forte@Sun.COM 			}
49957836SJohn.Forte@Sun.COM 			break;
49967836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LPORT:
49977836SJohn.Forte@Sun.COM 			if (!wait_queue)
49987836SJohn.Forte@Sun.COM 				task->task_lport->lport_task_poll(task);
49997836SJohn.Forte@Sun.COM 			break;
50007836SJohn.Forte@Sun.COM 		case ITASK_CMD_SEND_STATUS:
50017836SJohn.Forte@Sun.COM 		/* case ITASK_CMD_XFER_DATA: */
50027836SJohn.Forte@Sun.COM 			break;
50037836SJohn.Forte@Sun.COM 		}
50047836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
50057836SJohn.Forte@Sun.COM 		if (dec_qdepth) {
50067836SJohn.Forte@Sun.COM 			w->worker_queue_depth--;
50077836SJohn.Forte@Sun.COM 		}
50087836SJohn.Forte@Sun.COM 	}
50097836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) {
50107836SJohn.Forte@Sun.COM 		if (w->worker_ref_count == 0)
50117836SJohn.Forte@Sun.COM 			goto stmf_worker_loop;
50127836SJohn.Forte@Sun.COM 		else
50137836SJohn.Forte@Sun.COM 			wait_timer = ddi_get_lbolt() + 1;
50147836SJohn.Forte@Sun.COM 	}
50157836SJohn.Forte@Sun.COM 	w->worker_flags &= ~STMF_WORKER_ACTIVE;
50167836SJohn.Forte@Sun.COM 	if (wait_timer) {
50177836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer);
50187836SJohn.Forte@Sun.COM 	} else {
50197836SJohn.Forte@Sun.COM 		cv_wait(&w->worker_cv, &w->worker_lock);
50207836SJohn.Forte@Sun.COM 	}
50217836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_ACTIVE;
50227836SJohn.Forte@Sun.COM 	goto stmf_worker_loop;
50237836SJohn.Forte@Sun.COM }
50247836SJohn.Forte@Sun.COM 
50257836SJohn.Forte@Sun.COM void
50267836SJohn.Forte@Sun.COM stmf_worker_mgmt()
50277836SJohn.Forte@Sun.COM {
50287836SJohn.Forte@Sun.COM 	int i;
50297836SJohn.Forte@Sun.COM 	int workers_needed;
50307836SJohn.Forte@Sun.COM 	uint32_t qd;
50317836SJohn.Forte@Sun.COM 	clock_t tps, d = 0;
50327836SJohn.Forte@Sun.COM 	uint32_t cur_max_ntasks = 0;
50337836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
50347836SJohn.Forte@Sun.COM 
50357836SJohn.Forte@Sun.COM 	/* Check if we are trying to increase the # of threads */
50367836SJohn.Forte@Sun.COM 	for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) {
50377836SJohn.Forte@Sun.COM 		if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) {
50387836SJohn.Forte@Sun.COM 			stmf_nworkers_cur++;
50397836SJohn.Forte@Sun.COM 			stmf_nworkers_accepting_cmds++;
50407836SJohn.Forte@Sun.COM 		} else {
50417836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
50427836SJohn.Forte@Sun.COM 			return;
50437836SJohn.Forte@Sun.COM 		}
50447836SJohn.Forte@Sun.COM 	}
50457836SJohn.Forte@Sun.COM 	/* Check if we are trying to decrease the # of workers */
50467836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
50477836SJohn.Forte@Sun.COM 		if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) {
50487836SJohn.Forte@Sun.COM 			stmf_nworkers_cur--;
50497836SJohn.Forte@Sun.COM 			/*
50507836SJohn.Forte@Sun.COM 			 * stmf_nworkers_accepting_cmds has already been
50517836SJohn.Forte@Sun.COM 			 * updated by the request to reduce the # of workers.
50527836SJohn.Forte@Sun.COM 			 */
50537836SJohn.Forte@Sun.COM 		} else {
50547836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
50557836SJohn.Forte@Sun.COM 			return;
50567836SJohn.Forte@Sun.COM 		}
50577836SJohn.Forte@Sun.COM 	}
50587836SJohn.Forte@Sun.COM 	/* Check if we are being asked to quit */
50597836SJohn.Forte@Sun.COM 	if (stmf_workers_state != STMF_WORKERS_ENABLED) {
50607836SJohn.Forte@Sun.COM 		if (stmf_nworkers_cur) {
50617836SJohn.Forte@Sun.COM 			workers_needed = 0;
50627836SJohn.Forte@Sun.COM 			goto worker_mgmt_trigger_change;
50637836SJohn.Forte@Sun.COM 		}
50647836SJohn.Forte@Sun.COM 		return;
50657836SJohn.Forte@Sun.COM 	}
50667836SJohn.Forte@Sun.COM 	/* Check if we are starting */
50677836SJohn.Forte@Sun.COM 	if (stmf_nworkers_cur < stmf_i_min_nworkers) {
50687836SJohn.Forte@Sun.COM 		workers_needed = stmf_i_min_nworkers;
50697836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
50707836SJohn.Forte@Sun.COM 	}
50717836SJohn.Forte@Sun.COM 
50727836SJohn.Forte@Sun.COM 	tps = drv_usectohz(1 * 1000 * 1000);
50737836SJohn.Forte@Sun.COM 	if ((stmf_wm_last != 0) &&
50747836SJohn.Forte@Sun.COM 	    ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) {
50757836SJohn.Forte@Sun.COM 		qd = 0;
50767836SJohn.Forte@Sun.COM 		for (i = 0; i < stmf_nworkers_accepting_cmds; i++) {
50777836SJohn.Forte@Sun.COM 			qd += stmf_workers[i].worker_max_qdepth_pu;
50787836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_qdepth_pu = 0;
50797836SJohn.Forte@Sun.COM 			if (stmf_workers[i].worker_max_sys_qdepth_pu >
50807836SJohn.Forte@Sun.COM 			    cur_max_ntasks) {
50817836SJohn.Forte@Sun.COM 				cur_max_ntasks =
50827836SJohn.Forte@Sun.COM 				    stmf_workers[i].worker_max_sys_qdepth_pu;
50837836SJohn.Forte@Sun.COM 			}
50847836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_sys_qdepth_pu = 0;
50857836SJohn.Forte@Sun.COM 		}
50867836SJohn.Forte@Sun.COM 	}
50877836SJohn.Forte@Sun.COM 	stmf_wm_last = ddi_get_lbolt();
50887836SJohn.Forte@Sun.COM 	if (d <= tps) {
50897836SJohn.Forte@Sun.COM 		/* still ramping up */
50907836SJohn.Forte@Sun.COM 		return;
50917836SJohn.Forte@Sun.COM 	}
50927836SJohn.Forte@Sun.COM 	/* max qdepth cannot be more than max tasks */
50937836SJohn.Forte@Sun.COM 	if (qd > cur_max_ntasks)
50947836SJohn.Forte@Sun.COM 		qd = cur_max_ntasks;
50957836SJohn.Forte@Sun.COM 
50967836SJohn.Forte@Sun.COM 	/* See if we have more workers */
50977836SJohn.Forte@Sun.COM 	if (qd < stmf_nworkers_accepting_cmds) {
50987836SJohn.Forte@Sun.COM 		/*
50997836SJohn.Forte@Sun.COM 		 * Since we dont reduce the worker count right away, monitor
51007836SJohn.Forte@Sun.COM 		 * the highest load during the scale_down_delay.
51017836SJohn.Forte@Sun.COM 		 */
51027836SJohn.Forte@Sun.COM 		if (qd > stmf_worker_scale_down_qd)
51037836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = qd;
51047836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_timer == 0) {
51057836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_timer = ddi_get_lbolt() +
51067836SJohn.Forte@Sun.COM 			    drv_usectohz(stmf_worker_scale_down_delay *
51077836SJohn.Forte@Sun.COM 			    1000 * 1000);
51087836SJohn.Forte@Sun.COM 			return;
51097836SJohn.Forte@Sun.COM 		}
51107836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() < stmf_worker_scale_down_timer) {
51117836SJohn.Forte@Sun.COM 			return;
51127836SJohn.Forte@Sun.COM 		}
51137836SJohn.Forte@Sun.COM 		/* Its time to reduce the workers */
51147836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd < stmf_i_min_nworkers)
51157836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_min_nworkers;
51167836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd > stmf_i_max_nworkers)
51177836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_max_nworkers;
51187836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd == stmf_nworkers_cur)
51197836SJohn.Forte@Sun.COM 			return;
51207836SJohn.Forte@Sun.COM 		workers_needed = stmf_worker_scale_down_qd;
51217836SJohn.Forte@Sun.COM 		stmf_worker_scale_down_qd = 0;
51227836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
51237836SJohn.Forte@Sun.COM 	}
51247836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_qd = 0;
51257836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_timer = 0;
51267836SJohn.Forte@Sun.COM 	if (qd > stmf_i_max_nworkers)
51277836SJohn.Forte@Sun.COM 		qd = stmf_i_max_nworkers;
51287836SJohn.Forte@Sun.COM 	if (qd < stmf_i_min_nworkers)
51297836SJohn.Forte@Sun.COM 		qd = stmf_i_min_nworkers;
51307836SJohn.Forte@Sun.COM 	if (qd == stmf_nworkers_cur)
51317836SJohn.Forte@Sun.COM 		return;
51327836SJohn.Forte@Sun.COM 	workers_needed = qd;
51337836SJohn.Forte@Sun.COM 	goto worker_mgmt_trigger_change;
51347836SJohn.Forte@Sun.COM 
51357836SJohn.Forte@Sun.COM 	/* NOTREACHED */
51367836SJohn.Forte@Sun.COM 	return;
51377836SJohn.Forte@Sun.COM 
51387836SJohn.Forte@Sun.COM worker_mgmt_trigger_change:
51397836SJohn.Forte@Sun.COM 	ASSERT(workers_needed != stmf_nworkers_cur);
51407836SJohn.Forte@Sun.COM 	if (workers_needed > stmf_nworkers_cur) {
51417836SJohn.Forte@Sun.COM 		stmf_nworkers_needed = workers_needed;
51427836SJohn.Forte@Sun.COM 		for (i = stmf_nworkers_cur; i < workers_needed; i++) {
51437836SJohn.Forte@Sun.COM 			w = &stmf_workers[i];
51447836SJohn.Forte@Sun.COM 			w->worker_tid = thread_create(NULL, 0, stmf_worker_task,
51457836SJohn.Forte@Sun.COM 			    (void *)&stmf_workers[i], 0, &p0, TS_RUN,
51467836SJohn.Forte@Sun.COM 			    minclsyspri);
51477836SJohn.Forte@Sun.COM 		}
51487836SJohn.Forte@Sun.COM 		return;
51497836SJohn.Forte@Sun.COM 	}
51507836SJohn.Forte@Sun.COM 	/* At this point we know that we are decreasing the # of workers */
51517836SJohn.Forte@Sun.COM 	stmf_nworkers_accepting_cmds = workers_needed;
51527836SJohn.Forte@Sun.COM 	stmf_nworkers_needed = workers_needed;
51537836SJohn.Forte@Sun.COM 	/* Signal the workers that its time to quit */
51547836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
51557836SJohn.Forte@Sun.COM 		w = &stmf_workers[i];
51567836SJohn.Forte@Sun.COM 		ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED));
51577836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
51587836SJohn.Forte@Sun.COM 		w->worker_flags |= STMF_WORKER_TERMINATE;
51597836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
51607836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
51617836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
51627836SJohn.Forte@Sun.COM 	}
51637836SJohn.Forte@Sun.COM }
51647836SJohn.Forte@Sun.COM 
51657836SJohn.Forte@Sun.COM /*
51667836SJohn.Forte@Sun.COM  * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private).
51677836SJohn.Forte@Sun.COM  * If all the data has been filled out, frees the xd and makes
51687836SJohn.Forte@Sun.COM  * db_lu_private NULL.
51697836SJohn.Forte@Sun.COM  */
51707836SJohn.Forte@Sun.COM void
51717836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf)
51727836SJohn.Forte@Sun.COM {
51737836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
51747836SJohn.Forte@Sun.COM 	uint8_t *p;
51757836SJohn.Forte@Sun.COM 	int i;
51767836SJohn.Forte@Sun.COM 	uint32_t s;
51777836SJohn.Forte@Sun.COM 
51787836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
51797836SJohn.Forte@Sun.COM 	dbuf->db_data_size = 0;
51807836SJohn.Forte@Sun.COM 	dbuf->db_relative_offset = xd->size_done;
51817836SJohn.Forte@Sun.COM 	for (i = 0; i < dbuf->db_sglist_length; i++) {
51827836SJohn.Forte@Sun.COM 		s = min(xd->size_left, dbuf->db_sglist[i].seg_length);
51837836SJohn.Forte@Sun.COM 		p = &xd->buf[xd->size_done];
51847836SJohn.Forte@Sun.COM 		bcopy(p, dbuf->db_sglist[i].seg_addr, s);
51857836SJohn.Forte@Sun.COM 		xd->size_left -= s;
51867836SJohn.Forte@Sun.COM 		xd->size_done += s;
51877836SJohn.Forte@Sun.COM 		dbuf->db_data_size += s;
51887836SJohn.Forte@Sun.COM 		if (xd->size_left == 0) {
51897836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
51907836SJohn.Forte@Sun.COM 			dbuf->db_lu_private = NULL;
51917836SJohn.Forte@Sun.COM 			return;
51927836SJohn.Forte@Sun.COM 		}
51937836SJohn.Forte@Sun.COM 	}
51947836SJohn.Forte@Sun.COM }
51957836SJohn.Forte@Sun.COM 
51967836SJohn.Forte@Sun.COM /* ARGSUSED */
51977836SJohn.Forte@Sun.COM stmf_status_t
51987836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task)
51997836SJohn.Forte@Sun.COM {
52007836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
52017836SJohn.Forte@Sun.COM }
52027836SJohn.Forte@Sun.COM 
52037836SJohn.Forte@Sun.COM void
52047836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
52057836SJohn.Forte@Sun.COM {
52067836SJohn.Forte@Sun.COM 	uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
52077836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
52087836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
52097836SJohn.Forte@Sun.COM 	uint8_t *p;
52107836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
52117836SJohn.Forte@Sun.COM 	uint8_t inq_page_length = 31;
52127836SJohn.Forte@Sun.COM 
52137836SJohn.Forte@Sun.COM 	if (task->task_mgmt_function) {
52147836SJohn.Forte@Sun.COM 		stmf_scsilib_handle_task_mgmt(task);
52157836SJohn.Forte@Sun.COM 		return;
52167836SJohn.Forte@Sun.COM 	}
52177836SJohn.Forte@Sun.COM 
52187836SJohn.Forte@Sun.COM 	switch (cdbp[0]) {
52197836SJohn.Forte@Sun.COM 	case SCMD_INQUIRY:
52207836SJohn.Forte@Sun.COM 		/*
52217836SJohn.Forte@Sun.COM 		 * Basic protocol checks.  In addition, only reply to
52227836SJohn.Forte@Sun.COM 		 * standard inquiry.  Otherwise, the LU provider needs
52237836SJohn.Forte@Sun.COM 		 * to respond.
52247836SJohn.Forte@Sun.COM 		 */
52257836SJohn.Forte@Sun.COM 
52267836SJohn.Forte@Sun.COM 		if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) {
52277836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
52287836SJohn.Forte@Sun.COM 			    STMF_SAA_INVALID_FIELD_IN_CDB);
52297836SJohn.Forte@Sun.COM 			return;
52307836SJohn.Forte@Sun.COM 		}
52317836SJohn.Forte@Sun.COM 
52327836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
52337836SJohn.Forte@Sun.COM 		    (((uint32_t)cdbp[3]) << 8) | cdbp[4];
52347836SJohn.Forte@Sun.COM 
52357836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
52367836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
52377836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
52387836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
52397836SJohn.Forte@Sun.COM 		}
52407836SJohn.Forte@Sun.COM 
52417836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
52427836SJohn.Forte@Sun.COM 		    min(36, task->task_cmd_xfer_length));
52437836SJohn.Forte@Sun.COM 		minsz = 36;
52447836SJohn.Forte@Sun.COM 
52457836SJohn.Forte@Sun.COM 		if (sz == 0) {
52467836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
52477836SJohn.Forte@Sun.COM 			return;
52487836SJohn.Forte@Sun.COM 		}
52497836SJohn.Forte@Sun.COM 
52507836SJohn.Forte@Sun.COM 		if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) {
52517836SJohn.Forte@Sun.COM 			/*
52527836SJohn.Forte@Sun.COM 			 * Ignore any preallocated dbuf if the size is less
52537836SJohn.Forte@Sun.COM 			 * than 36. It will be freed during the task_free.
52547836SJohn.Forte@Sun.COM 			 */
52557836SJohn.Forte@Sun.COM 			dbuf = NULL;
52567836SJohn.Forte@Sun.COM 		}
52577836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
52587836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0);
52597836SJohn.Forte@Sun.COM 		if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) {
52607836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
52617836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
52627836SJohn.Forte@Sun.COM 			return;
52637836SJohn.Forte@Sun.COM 		}
52647836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = NULL;
52657836SJohn.Forte@Sun.COM 
52667836SJohn.Forte@Sun.COM 		p = dbuf->db_sglist[0].seg_addr;
52677836SJohn.Forte@Sun.COM 
52687836SJohn.Forte@Sun.COM 		/*
52697836SJohn.Forte@Sun.COM 		 * Standard inquiry handling only.
52707836SJohn.Forte@Sun.COM 		 */
52717836SJohn.Forte@Sun.COM 
52727836SJohn.Forte@Sun.COM 		bzero(p, inq_page_length + 5);
52737836SJohn.Forte@Sun.COM 
52747836SJohn.Forte@Sun.COM 		p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN;
52757836SJohn.Forte@Sun.COM 		p[2] = 5;
52767836SJohn.Forte@Sun.COM 		p[3] = 0x12;
52777836SJohn.Forte@Sun.COM 		p[4] = inq_page_length;
52787836SJohn.Forte@Sun.COM 		p[6] = 0x80;
52797836SJohn.Forte@Sun.COM 
52807836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+8, "SUN     ", 8);
52817836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+16, "COMSTAR	       ", 16);
52827836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+32, "1.0 ", 4);
52837836SJohn.Forte@Sun.COM 
52847836SJohn.Forte@Sun.COM 		dbuf->db_data_size = sz;
52857836SJohn.Forte@Sun.COM 		dbuf->db_relative_offset = 0;
52867836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
52877836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
52887836SJohn.Forte@Sun.COM 
52897836SJohn.Forte@Sun.COM 		return;
52907836SJohn.Forte@Sun.COM 
52917836SJohn.Forte@Sun.COM 	case SCMD_REPORT_LUNS:
52927836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
52937836SJohn.Forte@Sun.COM 		    ((((uint32_t)task->task_cdb[6]) << 24) |
52947836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[7]) << 16) |
52957836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[8]) << 8) |
52967836SJohn.Forte@Sun.COM 		    ((uint32_t)task->task_cdb[9]));
52977836SJohn.Forte@Sun.COM 
52987836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
52997836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
53007836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
53017836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
53027836SJohn.Forte@Sun.COM 		}
53037836SJohn.Forte@Sun.COM 
53047836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
53057836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length);
53067836SJohn.Forte@Sun.COM 
53077836SJohn.Forte@Sun.COM 		if (sz < 16) {
53087836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
53098662SJordan.Vaughan@Sun.com 			    STMF_SAA_INVALID_FIELD_IN_CDB);
53107836SJohn.Forte@Sun.COM 			return;
53117836SJohn.Forte@Sun.COM 		}
53127836SJohn.Forte@Sun.COM 
53137836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)
53147836SJohn.Forte@Sun.COM 		    task->task_session->ss_stmf_private;
53157836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
53167836SJohn.Forte@Sun.COM 		xd = stmf_session_prepare_report_lun_data(iss->iss_sm);
53177836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
53187836SJohn.Forte@Sun.COM 
53197836SJohn.Forte@Sun.COM 		if (xd == NULL) {
53207836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53217836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
53227836SJohn.Forte@Sun.COM 			return;
53237836SJohn.Forte@Sun.COM 		}
53247836SJohn.Forte@Sun.COM 
53257836SJohn.Forte@Sun.COM 		sz = min(sz, xd->size_left);
53267836SJohn.Forte@Sun.COM 		xd->size_left = sz;
53277836SJohn.Forte@Sun.COM 		minsz = min(512, sz);
53287836SJohn.Forte@Sun.COM 
53297836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
53307836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
53317836SJohn.Forte@Sun.COM 		if (dbuf == NULL) {
53327836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
53337836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53347836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
53357836SJohn.Forte@Sun.COM 			return;
53367836SJohn.Forte@Sun.COM 		}
53377836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = xd;
53387836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
53397836SJohn.Forte@Sun.COM 
53407836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags,
53418662SJordan.Vaughan@Sun.com 		    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
53427836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
53437836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
53447836SJohn.Forte@Sun.COM 		return;
53457836SJohn.Forte@Sun.COM 	}
53467836SJohn.Forte@Sun.COM 
53477836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE);
53487836SJohn.Forte@Sun.COM }
53497836SJohn.Forte@Sun.COM 
53507836SJohn.Forte@Sun.COM void
53517836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf)
53527836SJohn.Forte@Sun.COM {
53537836SJohn.Forte@Sun.COM 	if (dbuf->db_xfer_status != STMF_SUCCESS) {
53547836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53557836SJohn.Forte@Sun.COM 		    dbuf->db_xfer_status, NULL);
53567836SJohn.Forte@Sun.COM 		return;
53577836SJohn.Forte@Sun.COM 	}
53587836SJohn.Forte@Sun.COM 	task->task_nbytes_transferred = dbuf->db_data_size;
53597836SJohn.Forte@Sun.COM 	if (dbuf->db_lu_private) {
53607836SJohn.Forte@Sun.COM 		/* There is more */
53617836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
53627836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
53637836SJohn.Forte@Sun.COM 		return;
53647836SJohn.Forte@Sun.COM 	}
53657836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
53667836SJohn.Forte@Sun.COM }
53677836SJohn.Forte@Sun.COM 
53687836SJohn.Forte@Sun.COM /* ARGSUSED */
53697836SJohn.Forte@Sun.COM void
53707836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task)
53717836SJohn.Forte@Sun.COM {
53727836SJohn.Forte@Sun.COM }
53737836SJohn.Forte@Sun.COM 
53747836SJohn.Forte@Sun.COM /* ARGSUSED */
53757836SJohn.Forte@Sun.COM void
53767836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task)
53777836SJohn.Forte@Sun.COM {
53787836SJohn.Forte@Sun.COM }
53797836SJohn.Forte@Sun.COM 
53807836SJohn.Forte@Sun.COM /* ARGSUSED */
53817836SJohn.Forte@Sun.COM stmf_status_t
53827836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
53837836SJohn.Forte@Sun.COM {
53847836SJohn.Forte@Sun.COM 	scsi_task_t *task = (scsi_task_t *)arg;
53857836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
53868662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
53877836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
53887836SJohn.Forte@Sun.COM 	int i;
53897836SJohn.Forte@Sun.COM 	uint8_t map;
53907836SJohn.Forte@Sun.COM 
53917836SJohn.Forte@Sun.COM 	ASSERT(abort_cmd == STMF_LU_ABORT_TASK);
53927836SJohn.Forte@Sun.COM 	if ((task->task_mgmt_function) && (itask->itask_flags &
53937836SJohn.Forte@Sun.COM 	    (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) {
53947836SJohn.Forte@Sun.COM 		switch (task->task_mgmt_function) {
53957836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK:
53967836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK_SET:
53977836SJohn.Forte@Sun.COM 		case TM_CLEAR_TASK_SET:
53987836SJohn.Forte@Sun.COM 		case TM_LUN_RESET:
53997836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
54007836SJohn.Forte@Sun.COM 			break;
54017836SJohn.Forte@Sun.COM 		case TM_TARGET_RESET:
54027836SJohn.Forte@Sun.COM 		case TM_TARGET_COLD_RESET:
54037836SJohn.Forte@Sun.COM 		case TM_TARGET_WARM_RESET:
54047836SJohn.Forte@Sun.COM 			stmf_abort_target_reset(task);
54057836SJohn.Forte@Sun.COM 			break;
54067836SJohn.Forte@Sun.COM 		}
54077836SJohn.Forte@Sun.COM 		return (STMF_ABORT_SUCCESS);
54087836SJohn.Forte@Sun.COM 	}
54097836SJohn.Forte@Sun.COM 
54107836SJohn.Forte@Sun.COM 	/*
54117836SJohn.Forte@Sun.COM 	 * OK so its not a task mgmt. Make sure we free any xd sitting
54127836SJohn.Forte@Sun.COM 	 * inside any dbuf.
54137836SJohn.Forte@Sun.COM 	 */
54147836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
54157836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
54167836SJohn.Forte@Sun.COM 			if ((map & 1) &&
54177836SJohn.Forte@Sun.COM 			    ((itask->itask_dbufs[i])->db_lu_private)) {
54187836SJohn.Forte@Sun.COM 				stmf_xfer_data_t *xd;
54197836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
54207836SJohn.Forte@Sun.COM 
54217836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
54227836SJohn.Forte@Sun.COM 				xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
54237836SJohn.Forte@Sun.COM 				dbuf->db_lu_private = NULL;
54247836SJohn.Forte@Sun.COM 				kmem_free(xd, xd->alloc_size);
54257836SJohn.Forte@Sun.COM 			}
54267836SJohn.Forte@Sun.COM 			map >>= 1;
54277836SJohn.Forte@Sun.COM 		}
54287836SJohn.Forte@Sun.COM 	}
54297836SJohn.Forte@Sun.COM 	return (STMF_ABORT_SUCCESS);
54307836SJohn.Forte@Sun.COM }
54317836SJohn.Forte@Sun.COM 
54327836SJohn.Forte@Sun.COM void
54337836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task)
54347836SJohn.Forte@Sun.COM {
54357836SJohn.Forte@Sun.COM 	/* Right now we only do this for handling task management functions */
54367836SJohn.Forte@Sun.COM 	ASSERT(task->task_mgmt_function);
54377836SJohn.Forte@Sun.COM 
54387836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
54397836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
54407836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
54417836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
54427836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
54437836SJohn.Forte@Sun.COM 		(void) stmf_lun_reset_poll(task->task_lu, task, 0);
54447836SJohn.Forte@Sun.COM 		return;
54457836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
54467836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
54477836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
54487836SJohn.Forte@Sun.COM 		stmf_target_reset_poll(task);
54497836SJohn.Forte@Sun.COM 		return;
54507836SJohn.Forte@Sun.COM 	}
54517836SJohn.Forte@Sun.COM }
54527836SJohn.Forte@Sun.COM 
54537836SJohn.Forte@Sun.COM /* ARGSUSED */
54547836SJohn.Forte@Sun.COM void
54557836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg)
54567836SJohn.Forte@Sun.COM {
54577836SJohn.Forte@Sun.COM 	/* This function will never be called */
54587836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd);
54597836SJohn.Forte@Sun.COM }
54607836SJohn.Forte@Sun.COM 
54617836SJohn.Forte@Sun.COM void
54627836SJohn.Forte@Sun.COM stmf_dlun_init()
54637836SJohn.Forte@Sun.COM {
54647836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
54657836SJohn.Forte@Sun.COM 
54667836SJohn.Forte@Sun.COM 	dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0);
54677836SJohn.Forte@Sun.COM 	dlun0->lu_task_alloc = stmf_dlun0_task_alloc;
54687836SJohn.Forte@Sun.COM 	dlun0->lu_new_task = stmf_dlun0_new_task;
54697836SJohn.Forte@Sun.COM 	dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done;
54707836SJohn.Forte@Sun.COM 	dlun0->lu_send_status_done = stmf_dlun0_status_done;
54717836SJohn.Forte@Sun.COM 	dlun0->lu_task_free = stmf_dlun0_task_free;
54727836SJohn.Forte@Sun.COM 	dlun0->lu_abort = stmf_dlun0_abort;
54737836SJohn.Forte@Sun.COM 	dlun0->lu_task_poll = stmf_dlun0_task_poll;
54747836SJohn.Forte@Sun.COM 	dlun0->lu_ctl = stmf_dlun0_ctl;
54757836SJohn.Forte@Sun.COM 
54767836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
54777836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
54787836SJohn.Forte@Sun.COM }
54797836SJohn.Forte@Sun.COM 
54807836SJohn.Forte@Sun.COM stmf_status_t
54817836SJohn.Forte@Sun.COM stmf_dlun_fini()
54827836SJohn.Forte@Sun.COM {
54837836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
54847836SJohn.Forte@Sun.COM 
54857836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
54867836SJohn.Forte@Sun.COM 
54877836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
54887836SJohn.Forte@Sun.COM 	if (ilu->ilu_ntasks) {
54897836SJohn.Forte@Sun.COM 		stmf_i_scsi_task_t *itask, *nitask;
54907836SJohn.Forte@Sun.COM 
54917836SJohn.Forte@Sun.COM 		nitask = ilu->ilu_tasks;
54927836SJohn.Forte@Sun.COM 		do {
54937836SJohn.Forte@Sun.COM 			itask = nitask;
54947836SJohn.Forte@Sun.COM 			nitask = itask->itask_lu_next;
54957836SJohn.Forte@Sun.COM 			dlun0->lu_task_free(itask->itask_task);
54967836SJohn.Forte@Sun.COM 			stmf_free(itask->itask_task);
54977836SJohn.Forte@Sun.COM 		} while (nitask != NULL);
54987836SJohn.Forte@Sun.COM 
54997836SJohn.Forte@Sun.COM 	}
55007836SJohn.Forte@Sun.COM 	stmf_free(dlun0);
55017836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
55027836SJohn.Forte@Sun.COM }
55037836SJohn.Forte@Sun.COM 
55047836SJohn.Forte@Sun.COM void
55057836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task)
55067836SJohn.Forte@Sun.COM {
55077836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
55088662SJordan.Vaughan@Sun.com 	    task->task_session->ss_stmf_private;
55097836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
55107836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
55117836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
55127836SJohn.Forte@Sun.COM 	int i;
55137836SJohn.Forte@Sun.COM 
55147836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
55157836SJohn.Forte@Sun.COM 
55167836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
55177836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
55187836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
55197836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
55207836SJohn.Forte@Sun.COM 			continue;
55217836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
55227836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
55237836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
55247836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
55257836SJohn.Forte@Sun.COM 		}
55267836SJohn.Forte@Sun.COM 	}
55277836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
55287836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
55297836SJohn.Forte@Sun.COM }
55307836SJohn.Forte@Sun.COM 
55317836SJohn.Forte@Sun.COM /*
55327836SJohn.Forte@Sun.COM  * The return value is only used by function managing target reset.
55337836SJohn.Forte@Sun.COM  */
55347836SJohn.Forte@Sun.COM stmf_status_t
55357836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset)
55367836SJohn.Forte@Sun.COM {
55377836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
55387836SJohn.Forte@Sun.COM 	int ntasks_pending;
55397836SJohn.Forte@Sun.COM 
55407836SJohn.Forte@Sun.COM 	ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free;
55417836SJohn.Forte@Sun.COM 	/*
55427836SJohn.Forte@Sun.COM 	 * This function is also used during Target reset. The idea is that
55437836SJohn.Forte@Sun.COM 	 * once all the commands are aborted, call the LU's reset entry
55447836SJohn.Forte@Sun.COM 	 * point (abort entry point with a reset flag). But if this Task
55457836SJohn.Forte@Sun.COM 	 * mgmt is running on this LU then all the tasks cannot be aborted.
55467836SJohn.Forte@Sun.COM 	 * one task (this task) will still be running which is OK.
55477836SJohn.Forte@Sun.COM 	 */
55487836SJohn.Forte@Sun.COM 	if ((ntasks_pending == 0) || ((task->task_lu == lu) &&
55497836SJohn.Forte@Sun.COM 	    (ntasks_pending == 1))) {
55507836SJohn.Forte@Sun.COM 		stmf_status_t ret;
55517836SJohn.Forte@Sun.COM 
55527836SJohn.Forte@Sun.COM 		if ((task->task_mgmt_function == TM_LUN_RESET) ||
55537836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_RESET) ||
55547836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_WARM_RESET) ||
55557836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_COLD_RESET)) {
55567836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0);
55577836SJohn.Forte@Sun.COM 		} else {
55587836SJohn.Forte@Sun.COM 			ret = STMF_SUCCESS;
55597836SJohn.Forte@Sun.COM 		}
55607836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
55617836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
55627836SJohn.Forte@Sun.COM 		}
55637836SJohn.Forte@Sun.COM 		if (target_reset) {
55647836SJohn.Forte@Sun.COM 			return (ret);
55657836SJohn.Forte@Sun.COM 		}
55667836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
55677836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
55687836SJohn.Forte@Sun.COM 			return (ret);
55697836SJohn.Forte@Sun.COM 		}
55707836SJohn.Forte@Sun.COM 		if (ret != STMF_BUSY) {
55717836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL);
55727836SJohn.Forte@Sun.COM 			return (ret);
55737836SJohn.Forte@Sun.COM 		}
55747836SJohn.Forte@Sun.COM 	}
55757836SJohn.Forte@Sun.COM 
55767836SJohn.Forte@Sun.COM 	if (target_reset) {
55777836SJohn.Forte@Sun.COM 		/* Tell target reset polling code that we are not done */
55787836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
55797836SJohn.Forte@Sun.COM 	}
55807836SJohn.Forte@Sun.COM 
55817836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
55827836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
55837836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
55847836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
55857836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
55867836SJohn.Forte@Sun.COM 	}
55877836SJohn.Forte@Sun.COM 
55887836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
55897836SJohn.Forte@Sun.COM }
55907836SJohn.Forte@Sun.COM 
55917836SJohn.Forte@Sun.COM void
55927836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task)
55937836SJohn.Forte@Sun.COM {
55947836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
55958662SJordan.Vaughan@Sun.com 	    task->task_session->ss_stmf_private;
55967836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
55977836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
55987836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
55997836SJohn.Forte@Sun.COM 	stmf_status_t ret;
56007836SJohn.Forte@Sun.COM 	int i;
56017836SJohn.Forte@Sun.COM 	int not_done = 0;
56027836SJohn.Forte@Sun.COM 
56037836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
56047836SJohn.Forte@Sun.COM 
56057836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
56067836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
56077836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
56087836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
56097836SJohn.Forte@Sun.COM 			continue;
56107836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
56117836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
56127836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
56137836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
56147836SJohn.Forte@Sun.COM 			ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1);
56157836SJohn.Forte@Sun.COM 			rw_enter(iss->iss_lockp, RW_READER);
56167836SJohn.Forte@Sun.COM 			if (ret == STMF_SUCCESS)
56177836SJohn.Forte@Sun.COM 				continue;
56187836SJohn.Forte@Sun.COM 			not_done = 1;
56197836SJohn.Forte@Sun.COM 			if (ret != STMF_BUSY) {
56207836SJohn.Forte@Sun.COM 				rw_exit(iss->iss_lockp);
56217836SJohn.Forte@Sun.COM 				stmf_abort(STMF_QUEUE_TASK_ABORT, task,
56227836SJohn.Forte@Sun.COM 				    STMF_ABORTED, NULL);
56237836SJohn.Forte@Sun.COM 				return;
56247836SJohn.Forte@Sun.COM 			}
56257836SJohn.Forte@Sun.COM 		}
56267836SJohn.Forte@Sun.COM 	}
56277836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
56287836SJohn.Forte@Sun.COM 
56297836SJohn.Forte@Sun.COM 	if (not_done) {
56307836SJohn.Forte@Sun.COM 		if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
56317836SJohn.Forte@Sun.COM 		    != STMF_SUCCESS) {
56327836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
56337836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
56347836SJohn.Forte@Sun.COM 			return;
56357836SJohn.Forte@Sun.COM 		}
56367836SJohn.Forte@Sun.COM 		return;
56377836SJohn.Forte@Sun.COM 	}
56387836SJohn.Forte@Sun.COM 
56397836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
56407836SJohn.Forte@Sun.COM 
56417836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
56427836SJohn.Forte@Sun.COM }
56437836SJohn.Forte@Sun.COM 
56447836SJohn.Forte@Sun.COM stmf_status_t
56457836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid)
56467836SJohn.Forte@Sun.COM {
56477836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
56487836SJohn.Forte@Sun.COM 
56497836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56507836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56517836SJohn.Forte@Sun.COM 	}
56527836SJohn.Forte@Sun.COM 
56537836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid);
56547836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56557836SJohn.Forte@Sun.COM }
56567836SJohn.Forte@Sun.COM 
56577836SJohn.Forte@Sun.COM stmf_status_t
56587836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid)
56597836SJohn.Forte@Sun.COM {
56607836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
56617836SJohn.Forte@Sun.COM 
56627836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
56637836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl);
56647836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
56657836SJohn.Forte@Sun.COM 	}
56667836SJohn.Forte@Sun.COM 
56677836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56687836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56697836SJohn.Forte@Sun.COM 	}
56707836SJohn.Forte@Sun.COM 
56717836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid);
56727836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56737836SJohn.Forte@Sun.COM }
56747836SJohn.Forte@Sun.COM 
56757836SJohn.Forte@Sun.COM stmf_status_t
56767836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid)
56777836SJohn.Forte@Sun.COM {
56787836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
56798662SJordan.Vaughan@Sun.com 	    (stmf_i_local_port_t *)lport->lport_stmf_private;
56807836SJohn.Forte@Sun.COM 
56817836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56827836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56837836SJohn.Forte@Sun.COM 	}
56847836SJohn.Forte@Sun.COM 
56857836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid);
56867836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56877836SJohn.Forte@Sun.COM }
56887836SJohn.Forte@Sun.COM 
56897836SJohn.Forte@Sun.COM stmf_status_t
56907836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid)
56917836SJohn.Forte@Sun.COM {
56927836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
56938662SJordan.Vaughan@Sun.com 	    (stmf_i_local_port_t *)lport->lport_stmf_private;
56947836SJohn.Forte@Sun.COM 
56957836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
56967836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl);
56977836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
56987836SJohn.Forte@Sun.COM 	}
56997836SJohn.Forte@Sun.COM 
57007836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
57017836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
57027836SJohn.Forte@Sun.COM 	}
57037836SJohn.Forte@Sun.COM 
57047836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid);
57057836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
57067836SJohn.Forte@Sun.COM }
57077836SJohn.Forte@Sun.COM 
57087836SJohn.Forte@Sun.COM void
57097836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags)
57107836SJohn.Forte@Sun.COM {
57117836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) &&
57127836SJohn.Forte@Sun.COM 	    (ilu->ilu_lu->lu_event_handler != NULL)) {
57137836SJohn.Forte@Sun.COM 		ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags);
57147836SJohn.Forte@Sun.COM 	}
57157836SJohn.Forte@Sun.COM }
57167836SJohn.Forte@Sun.COM 
57177836SJohn.Forte@Sun.COM void
57187836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg,
57197836SJohn.Forte@Sun.COM 				uint32_t flags)
57207836SJohn.Forte@Sun.COM {
57217836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) &&
57227836SJohn.Forte@Sun.COM 	    (ilport->ilport_lport->lport_event_handler != NULL)) {
57237836SJohn.Forte@Sun.COM 		ilport->ilport_lport->lport_event_handler(
57247836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, eventid, arg, flags);
57257836SJohn.Forte@Sun.COM 	}
57267836SJohn.Forte@Sun.COM }
57277836SJohn.Forte@Sun.COM 
57287836SJohn.Forte@Sun.COM void
57297836SJohn.Forte@Sun.COM stmf_svc_init()
57307836SJohn.Forte@Sun.COM {
57317836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
57327836SJohn.Forte@Sun.COM 		return;
57337836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1,
57347836SJohn.Forte@Sun.COM 	    TASKQ_DEFAULTPRI, 0);
57357836SJohn.Forte@Sun.COM 	(void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq,
57367836SJohn.Forte@Sun.COM 	    stmf_svc, 0, DDI_SLEEP);
57377836SJohn.Forte@Sun.COM }
57387836SJohn.Forte@Sun.COM 
57397836SJohn.Forte@Sun.COM stmf_status_t
57407836SJohn.Forte@Sun.COM stmf_svc_fini()
57417836SJohn.Forte@Sun.COM {
57427836SJohn.Forte@Sun.COM 	uint32_t i;
57437836SJohn.Forte@Sun.COM 
57447836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
57457836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) {
57467836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE;
57477836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
57487836SJohn.Forte@Sun.COM 	}
57497836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
57507836SJohn.Forte@Sun.COM 
57517836SJohn.Forte@Sun.COM 	/* Wait for 5 seconds */
57527836SJohn.Forte@Sun.COM 	for (i = 0; i < 500; i++) {
57537836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
57547836SJohn.Forte@Sun.COM 			delay(drv_usectohz(10000));
57557836SJohn.Forte@Sun.COM 		else
57567836SJohn.Forte@Sun.COM 			break;
57577836SJohn.Forte@Sun.COM 	}
57587836SJohn.Forte@Sun.COM 	if (i == 500)
57597836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
57607836SJohn.Forte@Sun.COM 
57617836SJohn.Forte@Sun.COM 	ddi_taskq_destroy(stmf_state.stmf_svc_taskq);
57627836SJohn.Forte@Sun.COM 
57637836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
57647836SJohn.Forte@Sun.COM }
57657836SJohn.Forte@Sun.COM 
57667836SJohn.Forte@Sun.COM /* ARGSUSED */
57677836SJohn.Forte@Sun.COM void
57687836SJohn.Forte@Sun.COM stmf_svc(void *arg)
57697836SJohn.Forte@Sun.COM {
57707836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req, **preq;
57717836SJohn.Forte@Sun.COM 	clock_t td;
57727836SJohn.Forte@Sun.COM 	clock_t	drain_start, drain_next = 0;
57737836SJohn.Forte@Sun.COM 	clock_t	timing_start, timing_next = 0;
57747836SJohn.Forte@Sun.COM 	clock_t worker_delay = 0;
57757836SJohn.Forte@Sun.COM 	int deq;
57767836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
57777836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
57787836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport;
57797836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport, *next_ilport;
57807836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
57817836SJohn.Forte@Sun.COM 
57827836SJohn.Forte@Sun.COM 	td = drv_usectohz(20000);
57837836SJohn.Forte@Sun.COM 
57847836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
57857836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE;
57867836SJohn.Forte@Sun.COM 
57877836SJohn.Forte@Sun.COM stmf_svc_loop:
57887836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) {
57897836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &=
57907836SJohn.Forte@Sun.COM 		    ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE);
57917836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
57927836SJohn.Forte@Sun.COM 		return;
57937836SJohn.Forte@Sun.COM 	}
57947836SJohn.Forte@Sun.COM 
57957836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active) {
57967836SJohn.Forte@Sun.COM 		int waitq_add = 0;
57977836SJohn.Forte@Sun.COM 		req = stmf_state.stmf_svc_active;
57987836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_active = req->svc_next;
57997836SJohn.Forte@Sun.COM 
58007836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
58017836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
58027836SJohn.Forte@Sun.COM 			/* Fallthrough */
58037836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
58047836SJohn.Forte@Sun.COM 			/* Fallthrough */
58057836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
58067836SJohn.Forte@Sun.COM 			/* Nothing to do */
58077836SJohn.Forte@Sun.COM 			waitq_add = 1;
58087836SJohn.Forte@Sun.COM 			break;
58097836SJohn.Forte@Sun.COM 
58107836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
58117836SJohn.Forte@Sun.COM 			/* Remove all mappings of this LU */
58127836SJohn.Forte@Sun.COM 			stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj);
58137836SJohn.Forte@Sun.COM 			/* Kill all the pending I/Os for this LU */
58147836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
58157836SJohn.Forte@Sun.COM 			stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL,
58168662SJordan.Vaughan@Sun.com 			    STMF_ABORTED);
58177836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
58187836SJohn.Forte@Sun.COM 			waitq_add = 1;
58197836SJohn.Forte@Sun.COM 			break;
58207836SJohn.Forte@Sun.COM 		default:
58217836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d",
58227836SJohn.Forte@Sun.COM 			    req->svc_cmd);
58237836SJohn.Forte@Sun.COM 		}
58247836SJohn.Forte@Sun.COM 
58257836SJohn.Forte@Sun.COM 		if (waitq_add) {
58267836SJohn.Forte@Sun.COM 			/* Put it in the wait queue */
58277836SJohn.Forte@Sun.COM 			req->svc_next = stmf_state.stmf_svc_waiting;
58287836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_waiting = req;
58297836SJohn.Forte@Sun.COM 		}
58307836SJohn.Forte@Sun.COM 	}
58317836SJohn.Forte@Sun.COM 
58327836SJohn.Forte@Sun.COM 	/* The waiting list is not going to be modified by anybody else */
58337836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
58347836SJohn.Forte@Sun.COM 
58357836SJohn.Forte@Sun.COM 	for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) {
58367836SJohn.Forte@Sun.COM 		req = *preq;
58377836SJohn.Forte@Sun.COM 		deq = 0;
58387836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
58397836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
58407836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
58417836SJohn.Forte@Sun.COM 			deq = 1;
58427836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
58437836SJohn.Forte@Sun.COM 			break;
58447836SJohn.Forte@Sun.COM 
58457836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
58467836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
58477836SJohn.Forte@Sun.COM 			ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
58487836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
58497836SJohn.Forte@Sun.COM 				break;
58507836SJohn.Forte@Sun.COM 			deq = 1;
58517836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
58527836SJohn.Forte@Sun.COM 			break;
58537836SJohn.Forte@Sun.COM 
58547836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
58557836SJohn.Forte@Sun.COM 			/* Fallthrough */
58567836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
58577836SJohn.Forte@Sun.COM 			lport = (stmf_local_port_t *)req->svc_obj;
58587836SJohn.Forte@Sun.COM 			deq = 1;
58597836SJohn.Forte@Sun.COM 			lport->lport_ctl(lport, req->svc_cmd, &req->svc_info);
58607836SJohn.Forte@Sun.COM 			break;
58617836SJohn.Forte@Sun.COM 		}
58627836SJohn.Forte@Sun.COM 		if (deq) {
58637836SJohn.Forte@Sun.COM 			*preq = req->svc_next;
58647836SJohn.Forte@Sun.COM 			kmem_free(req, req->svc_req_alloc_size);
58657836SJohn.Forte@Sun.COM 		} else {
58667836SJohn.Forte@Sun.COM 			preq = &req->svc_next;
58677836SJohn.Forte@Sun.COM 		}
58687836SJohn.Forte@Sun.COM 	}
58697836SJohn.Forte@Sun.COM 
58707836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
58717836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active == NULL) {
58727836SJohn.Forte@Sun.COM 		/* Do timeouts */
58737836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
58747836SJohn.Forte@Sun.COM 		    ((!timing_next) || (ddi_get_lbolt() >= timing_next))) {
58757836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
58767836SJohn.Forte@Sun.COM 				/* we are starting a new round */
58777836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_timing =
58787836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
58797836SJohn.Forte@Sun.COM 				timing_start = ddi_get_lbolt();
58807836SJohn.Forte@Sun.COM 			}
58817836SJohn.Forte@Sun.COM 			stmf_check_ilu_timing();
58827836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
58837836SJohn.Forte@Sun.COM 				/* we finished a complete round */
58847836SJohn.Forte@Sun.COM 				timing_next =
58857836SJohn.Forte@Sun.COM 				    timing_start + drv_usectohz(5*1000*1000);
58867836SJohn.Forte@Sun.COM 			} else {
58877836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
58887836SJohn.Forte@Sun.COM 				timing_next =
58897836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
58907836SJohn.Forte@Sun.COM 			}
58917836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
58927836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
58937836SJohn.Forte@Sun.COM 		}
58947836SJohn.Forte@Sun.COM 		/* Check if there are free tasks to clear */
58957836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
58967836SJohn.Forte@Sun.COM 		    ((!drain_next) || (ddi_get_lbolt() >= drain_next))) {
58977836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
58987836SJohn.Forte@Sun.COM 				/* we are starting a new round */
58997836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_draining =
59007836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
59017836SJohn.Forte@Sun.COM 				drain_start = ddi_get_lbolt();
59027836SJohn.Forte@Sun.COM 			}
59037836SJohn.Forte@Sun.COM 			stmf_check_freetask();
59047836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
59057836SJohn.Forte@Sun.COM 				/* we finished a complete round */
59067836SJohn.Forte@Sun.COM 				drain_next =
59077836SJohn.Forte@Sun.COM 				    drain_start + drv_usectohz(10*1000*1000);
59087836SJohn.Forte@Sun.COM 			} else {
59097836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
59107836SJohn.Forte@Sun.COM 				drain_next =
59117836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
59127836SJohn.Forte@Sun.COM 			}
59137836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
59147836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
59157836SJohn.Forte@Sun.COM 		}
59167836SJohn.Forte@Sun.COM 
59177836SJohn.Forte@Sun.COM 		/* Check if we need to run worker_mgmt */
59187836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > worker_delay) {
59197836SJohn.Forte@Sun.COM 			stmf_worker_mgmt();
59207836SJohn.Forte@Sun.COM 			worker_delay = ddi_get_lbolt() +
59217836SJohn.Forte@Sun.COM 			    stmf_worker_mgmt_delay;
59227836SJohn.Forte@Sun.COM 		}
59237836SJohn.Forte@Sun.COM 
59247836SJohn.Forte@Sun.COM 		/* Check if any active session got its 1st LUN */
59257836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_process_initial_luns) {
59267836SJohn.Forte@Sun.COM 			int stmf_level = 0;
59277836SJohn.Forte@Sun.COM 			int port_level;
59287836SJohn.Forte@Sun.COM 			for (ilport = stmf_state.stmf_ilportlist; ilport;
59297836SJohn.Forte@Sun.COM 			    ilport = next_ilport) {
59307836SJohn.Forte@Sun.COM 				next_ilport = ilport->ilport_next;
59317836SJohn.Forte@Sun.COM 				if ((ilport->ilport_flags &
59327836SJohn.Forte@Sun.COM 				    ILPORT_SS_GOT_INITIAL_LUNS) == 0) {
59337836SJohn.Forte@Sun.COM 					continue;
59347836SJohn.Forte@Sun.COM 				}
59357836SJohn.Forte@Sun.COM 				port_level = 0;
59367836SJohn.Forte@Sun.COM 				rw_enter(&ilport->ilport_lock, RW_READER);
59377836SJohn.Forte@Sun.COM 				for (iss = ilport->ilport_ss_list; iss;
59387836SJohn.Forte@Sun.COM 				    iss = iss->iss_next) {
59397836SJohn.Forte@Sun.COM 					if ((iss->iss_flags &
59407836SJohn.Forte@Sun.COM 					    ISS_GOT_INITIAL_LUNS) == 0) {
59417836SJohn.Forte@Sun.COM 						continue;
59427836SJohn.Forte@Sun.COM 					}
59437836SJohn.Forte@Sun.COM 					port_level++;
59447836SJohn.Forte@Sun.COM 					stmf_level++;
59457836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
59468662SJordan.Vaughan@Sun.com 					    ~ISS_GOT_INITIAL_LUNS);
59477836SJohn.Forte@Sun.COM 					atomic_or_32(&iss->iss_flags,
59488662SJordan.Vaughan@Sun.com 					    ISS_EVENT_ACTIVE);
59497836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
59507836SJohn.Forte@Sun.COM 					mutex_exit(&stmf_state.stmf_lock);
59517836SJohn.Forte@Sun.COM 					stmf_generate_lport_event(ilport,
59527836SJohn.Forte@Sun.COM 					    LPORT_EVENT_INITIAL_LUN_MAPPED,
59537836SJohn.Forte@Sun.COM 					    iss->iss_ss, 0);
59547836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
59558662SJordan.Vaughan@Sun.com 					    ~ISS_EVENT_ACTIVE);
59567836SJohn.Forte@Sun.COM 					mutex_enter(&stmf_state.stmf_lock);
59577836SJohn.Forte@Sun.COM 					/*
59587836SJohn.Forte@Sun.COM 					 * scan all the ilports again as the
59597836SJohn.Forte@Sun.COM 					 * ilport list might have changed.
59607836SJohn.Forte@Sun.COM 					 */
59617836SJohn.Forte@Sun.COM 					next_ilport =
59628662SJordan.Vaughan@Sun.com 					    stmf_state.stmf_ilportlist;
59637836SJohn.Forte@Sun.COM 					break;
59647836SJohn.Forte@Sun.COM 				}
59657836SJohn.Forte@Sun.COM 				if (port_level == 0) {
59667836SJohn.Forte@Sun.COM 					atomic_and_32(&ilport->ilport_flags,
59678662SJordan.Vaughan@Sun.com 					    ~ILPORT_SS_GOT_INITIAL_LUNS);
59687836SJohn.Forte@Sun.COM 				}
59697836SJohn.Forte@Sun.COM 				/* drop the lock if we are holding it. */
59707836SJohn.Forte@Sun.COM 				if (rw_lock_held(&ilport->ilport_lock))
59717836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
59727836SJohn.Forte@Sun.COM 
59737836SJohn.Forte@Sun.COM 				/* Max 4 session at a time */
59747836SJohn.Forte@Sun.COM 				if (stmf_level >= 4) {
59757836SJohn.Forte@Sun.COM 					break;
59767836SJohn.Forte@Sun.COM 				}
59777836SJohn.Forte@Sun.COM 			}
59787836SJohn.Forte@Sun.COM 			if (stmf_level == 0) {
59797836SJohn.Forte@Sun.COM 				stmf_state.stmf_process_initial_luns = 0;
59807836SJohn.Forte@Sun.COM 			}
59817836SJohn.Forte@Sun.COM 		}
59827836SJohn.Forte@Sun.COM 
59837836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE;
59847836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock,
59857836SJohn.Forte@Sun.COM 		    ddi_get_lbolt() + td);
59867836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
59877836SJohn.Forte@Sun.COM 	}
59887836SJohn.Forte@Sun.COM 	goto stmf_svc_loop;
59897836SJohn.Forte@Sun.COM }
59907836SJohn.Forte@Sun.COM 
59917836SJohn.Forte@Sun.COM void
59927836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
59937836SJohn.Forte@Sun.COM {
59947836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req;
59957836SJohn.Forte@Sun.COM 	int s;
59967836SJohn.Forte@Sun.COM 
59977836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&stmf_state.stmf_lock));
59987836SJohn.Forte@Sun.COM 	s = sizeof (stmf_svc_req_t);
59997836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
60007836SJohn.Forte@Sun.COM 		s += strlen(info->st_additional_info) + 1;
60017836SJohn.Forte@Sun.COM 	}
60027836SJohn.Forte@Sun.COM 	req = kmem_zalloc(s, KM_SLEEP);
60037836SJohn.Forte@Sun.COM 
60047836SJohn.Forte@Sun.COM 	req->svc_cmd = cmd;
60057836SJohn.Forte@Sun.COM 	req->svc_obj = obj;
60067836SJohn.Forte@Sun.COM 	req->svc_info.st_rflags = info->st_rflags;
60077836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
60087836SJohn.Forte@Sun.COM 		req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req,
60097836SJohn.Forte@Sun.COM 		    sizeof (stmf_svc_req_t)));
60107836SJohn.Forte@Sun.COM 		(void) strcpy(req->svc_info.st_additional_info,
60117836SJohn.Forte@Sun.COM 		    info->st_additional_info);
60127836SJohn.Forte@Sun.COM 	}
60137836SJohn.Forte@Sun.COM 	req->svc_req_alloc_size = s;
60147836SJohn.Forte@Sun.COM 
60157836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
60167836SJohn.Forte@Sun.COM 	req->svc_next = stmf_state.stmf_svc_active;
60177836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_active = req;
60187836SJohn.Forte@Sun.COM 	if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) {
60197836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
60207836SJohn.Forte@Sun.COM 	}
60217836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
60227836SJohn.Forte@Sun.COM }
60237836SJohn.Forte@Sun.COM 
60247836SJohn.Forte@Sun.COM void
60257836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...)
60267836SJohn.Forte@Sun.COM {
60277836SJohn.Forte@Sun.COM 	va_list args;
60287836SJohn.Forte@Sun.COM 	char tbuf[160];
60297836SJohn.Forte@Sun.COM 	int len;
60307836SJohn.Forte@Sun.COM 
60317836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
60327836SJohn.Forte@Sun.COM 		return;
60337836SJohn.Forte@Sun.COM 	len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "",
60347836SJohn.Forte@Sun.COM 	    ddi_get_lbolt());
60357836SJohn.Forte@Sun.COM 	va_start(args, fmt);
60367836SJohn.Forte@Sun.COM 	len += vsnprintf(tbuf + len, 158 - len, fmt, args);
60377836SJohn.Forte@Sun.COM 	va_end(args);
60387836SJohn.Forte@Sun.COM 
60397836SJohn.Forte@Sun.COM 	if (len > 158) {
60407836SJohn.Forte@Sun.COM 		len = 158;
60417836SJohn.Forte@Sun.COM 	}
60427836SJohn.Forte@Sun.COM 	tbuf[len++] = '\n';
60437836SJohn.Forte@Sun.COM 	tbuf[len] = 0;
60447836SJohn.Forte@Sun.COM 
60457836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
60467836SJohn.Forte@Sun.COM 	bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1);
60477836SJohn.Forte@Sun.COM 	trace_buf_curndx += len;
60487836SJohn.Forte@Sun.COM 	if (trace_buf_curndx > (trace_buf_size - 320))
60497836SJohn.Forte@Sun.COM 		trace_buf_curndx = 0;
60507836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
60517836SJohn.Forte@Sun.COM }
60527836SJohn.Forte@Sun.COM 
60537836SJohn.Forte@Sun.COM void
60547836SJohn.Forte@Sun.COM stmf_trace_clear()
60557836SJohn.Forte@Sun.COM {
60567836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
60577836SJohn.Forte@Sun.COM 		return;
60587836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
60597836SJohn.Forte@Sun.COM 	trace_buf_curndx = 0;
60607836SJohn.Forte@Sun.COM 	if (trace_buf_size > 0)
60617836SJohn.Forte@Sun.COM 		stmf_trace_buf[0] = 0;
60627836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
60637836SJohn.Forte@Sun.COM }
60647836SJohn.Forte@Sun.COM 
60657836SJohn.Forte@Sun.COM static void
60667836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info)
60677836SJohn.Forte@Sun.COM {
60687836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	 change_info;
60697836SJohn.Forte@Sun.COM 	void				*ctl_private;
60707836SJohn.Forte@Sun.COM 	uint32_t			 ctl_cmd;
60717836SJohn.Forte@Sun.COM 	int				msg = 0;
60727836SJohn.Forte@Sun.COM 
60737836SJohn.Forte@Sun.COM 	stmf_trace("FROM STMF", "abort_task_offline called for %s: %s",
60747836SJohn.Forte@Sun.COM 	    offline_lu ? "LU" : "LPORT", info ? info : "no additional info");
60757836SJohn.Forte@Sun.COM 	change_info.st_additional_info = info;
60767836SJohn.Forte@Sun.COM 	if (offline_lu) {
60777836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
60787836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LU_ABORT;
60797836SJohn.Forte@Sun.COM 		ctl_private = task->task_lu;
60807836SJohn.Forte@Sun.COM 		if (((stmf_i_lu_t *)
60817836SJohn.Forte@Sun.COM 		    task->task_lu->lu_stmf_private)->ilu_state ==
60827836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
60837836SJohn.Forte@Sun.COM 			msg = 1;
60847836SJohn.Forte@Sun.COM 		}
60857836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LU_OFFLINE;
60867836SJohn.Forte@Sun.COM 	} else {
60877836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
60887836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LPORT_ABORT;
60897836SJohn.Forte@Sun.COM 		ctl_private = task->task_lport;
60907836SJohn.Forte@Sun.COM 		if (((stmf_i_local_port_t *)
60917836SJohn.Forte@Sun.COM 		    task->task_lport->lport_stmf_private)->ilport_state ==
60927836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
60937836SJohn.Forte@Sun.COM 			msg = 1;
60947836SJohn.Forte@Sun.COM 		}
60957836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LPORT_OFFLINE;
60967836SJohn.Forte@Sun.COM 	}
60977836SJohn.Forte@Sun.COM 
60987836SJohn.Forte@Sun.COM 	if (msg) {
60997836SJohn.Forte@Sun.COM 		stmf_trace(0, "Calling stmf_ctl to offline %s : %s",
61007836SJohn.Forte@Sun.COM 		    offline_lu ? "LU" : "LPORT", info ? info :
61017836SJohn.Forte@Sun.COM 		    "<no additional info>");
61027836SJohn.Forte@Sun.COM 	}
61037836SJohn.Forte@Sun.COM 	(void) stmf_ctl(ctl_cmd, ctl_private, &change_info);
61047836SJohn.Forte@Sun.COM }
6105