xref: /onnv-gate/usr/src/uts/common/io/comstar/stmf/stmf.c (revision 9585:bf09620212ab)
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);
76*9585STim.Szeto@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
77*9585STim.Szeto@Sun.COM     uint32_t *err_ret);
787836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
79*9585STim.Szeto@Sun.COM int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
80*9585STim.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:
288*9585STim.Szeto@Sun.COM 		*result =
289*9585STim.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;
440*9585STim.Szeto@Sun.COM 	stmf_ppioctl_data_t *ppi, *ppi_out = NULL;
441*9585STim.Szeto@Sun.COM 	uint64_t *ppi_token = NULL;
442*9585STim.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:
473*9585STim.Szeto@Sun.COM 		/* retrieves both registered/unregistered */
474*9585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
475*9585STim.Szeto@Sun.COM 		id_list = &stmf_state.stmf_luid_list;
476*9585STim.Szeto@Sun.COM 		n = min(id_list->id_count,
477*9585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
478*9585STim.Szeto@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
479*9585STim.Szeto@Sun.COM 		luid_list = (slist_lu_t *)obuf;
480*9585STim.Szeto@Sun.COM 		id_entry = id_list->idl_head;
481*9585STim.Szeto@Sun.COM 		for (i = 0; i < n; i++) {
482*9585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
483*9585STim.Szeto@Sun.COM 			id_entry = id_entry->id_next;
484*9585STim.Szeto@Sun.COM 		}
485*9585STim.Szeto@Sun.COM 
486*9585STim.Szeto@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (slist_lu_t);
487*9585STim.Szeto@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
488*9585STim.Szeto@Sun.COM 			id = (uint8_t *)ilu->ilu_lu->lu_id;
489*9585STim.Szeto@Sun.COM 			if (stmf_lookup_id(id_list, 16, id + 4) == NULL) {
490*9585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
491*9585STim.Szeto@Sun.COM 				if (i < n) {
492*9585STim.Szeto@Sun.COM 					bcopy(id + 4, luid_list[i].lu_guid,
493*9585STim.Szeto@Sun.COM 					    sizeof (slist_lu_t));
494*9585STim.Szeto@Sun.COM 					i++;
495*9585STim.Szeto@Sun.COM 				}
496*9585STim.Szeto@Sun.COM 			}
497*9585STim.Szeto@Sun.COM 		}
498*9585STim.Szeto@Sun.COM 		iocd->stmf_obuf_nentries = i;
499*9585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
500*9585STim.Szeto@Sun.COM 		break;
501*9585STim.Szeto@Sun.COM 
502*9585STim.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 
519*9585STim.Szeto@Sun.COM 	case STMF_IOCTL_VE_LU_LIST:
520*9585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
521*9585STim.Szeto@Sun.COM 		id_list = &stmf_state.stmf_luid_list;
522*9585STim.Szeto@Sun.COM 		n = min(id_list->id_count,
523*9585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
524*9585STim.Szeto@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
525*9585STim.Szeto@Sun.COM 		iocd->stmf_obuf_nentries = n;
526*9585STim.Szeto@Sun.COM 		luid_list = (slist_lu_t *)obuf;
527*9585STim.Szeto@Sun.COM 		id_entry = id_list->idl_head;
528*9585STim.Szeto@Sun.COM 		for (i = 0; i < n; i++) {
529*9585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
530*9585STim.Szeto@Sun.COM 			id_entry = id_entry->id_next;
531*9585STim.Szeto@Sun.COM 		}
532*9585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
533*9585STim.Szeto@Sun.COM 		break;
534*9585STim.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 		if (idtype == STMF_ID_TYPE_TARGET &&
7997836SJohn.Forte@Sun.COM 		    stmf_state.stmf_service_running) {
8007836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
8017836SJohn.Forte@Sun.COM 			iocd->stmf_error =
8027836SJohn.Forte@Sun.COM 			    STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE;
8037836SJohn.Forte@Sun.COM 			ret = EBUSY;
8047836SJohn.Forte@Sun.COM 			break; /* not allowed */
8057836SJohn.Forte@Sun.COM 		}
8067836SJohn.Forte@Sun.COM 		ret = stmf_add_group_member(grp_entry->group.name,
8077836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
8087836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
8097836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
8107836SJohn.Forte@Sun.COM 		    idtype,
8117836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
8127836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8137836SJohn.Forte@Sun.COM 		break;
8147836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HG_ENTRY:
8157836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST;
8167836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8177836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TG_ENTRY:
8187836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8197836SJohn.Forte@Sun.COM 			ret = EACCES;
8207836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8217836SJohn.Forte@Sun.COM 			break;
8227836SJohn.Forte@Sun.COM 		}
8237836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) {
8247836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET;
8257836SJohn.Forte@Sun.COM 		}
8267836SJohn.Forte@Sun.COM 		grp_entry = (stmf_group_op_data_t *)ibuf;
8277836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8287836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
8297836SJohn.Forte@Sun.COM 			ret = EINVAL;
8307836SJohn.Forte@Sun.COM 			break;
8317836SJohn.Forte@Sun.COM 		}
8327836SJohn.Forte@Sun.COM 		if (grp_entry->group.name[0] == '*') {
8337836SJohn.Forte@Sun.COM 			ret = EINVAL;
8347836SJohn.Forte@Sun.COM 			break; /* not allowed */
8357836SJohn.Forte@Sun.COM 		}
8367836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8377836SJohn.Forte@Sun.COM 		if (idtype == STMF_ID_TYPE_TARGET &&
8387836SJohn.Forte@Sun.COM 		    stmf_state.stmf_service_running) {
8397836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
8407836SJohn.Forte@Sun.COM 			iocd->stmf_error =
8417836SJohn.Forte@Sun.COM 			    STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE;
8427836SJohn.Forte@Sun.COM 			ret = EBUSY;
8437836SJohn.Forte@Sun.COM 			break; /* not allowed */
8447836SJohn.Forte@Sun.COM 		}
8457836SJohn.Forte@Sun.COM 		ret = stmf_remove_group_member(grp_entry->group.name,
8467836SJohn.Forte@Sun.COM 		    grp_entry->group.name_size,
8477836SJohn.Forte@Sun.COM 		    grp_entry->ident + 4,
8487836SJohn.Forte@Sun.COM 		    grp_entry->ident[3],
8497836SJohn.Forte@Sun.COM 		    idtype,
8507836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
8517836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8527836SJohn.Forte@Sun.COM 		break;
8537836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_HOST_GROUP:
8547836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
8557836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8567836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CREATE_TARGET_GROUP:
8577836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8587836SJohn.Forte@Sun.COM 			ret = EACCES;
8597836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8607836SJohn.Forte@Sun.COM 			break;
8617836SJohn.Forte@Sun.COM 		}
8627836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8637836SJohn.Forte@Sun.COM 
8647836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP)
8657836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8667836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8677836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8687836SJohn.Forte@Sun.COM 			ret = EINVAL;
8697836SJohn.Forte@Sun.COM 			break;
8707836SJohn.Forte@Sun.COM 		}
8717836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8727836SJohn.Forte@Sun.COM 			ret = EINVAL;
8737836SJohn.Forte@Sun.COM 			break; /* not allowed */
8747836SJohn.Forte@Sun.COM 		}
8757836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
8767836SJohn.Forte@Sun.COM 		ret = stmf_add_group(grpname->name,
8777836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
8787836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
8797836SJohn.Forte@Sun.COM 		break;
8807836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_HOST_GROUP:
8817836SJohn.Forte@Sun.COM 		idtype = STMF_ID_TYPE_HOST_GROUP;
8827836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
8837836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_TARGET_GROUP:
8847836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
8857836SJohn.Forte@Sun.COM 			ret = EACCES;
8867836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
8877836SJohn.Forte@Sun.COM 			break;
8887836SJohn.Forte@Sun.COM 		}
8897836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
8907836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP)
8917836SJohn.Forte@Sun.COM 			idtype = STMF_ID_TYPE_TARGET_GROUP;
8927836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
8937836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
8947836SJohn.Forte@Sun.COM 			ret = EINVAL;
8957836SJohn.Forte@Sun.COM 			break;
8967836SJohn.Forte@Sun.COM 		}
8977836SJohn.Forte@Sun.COM 		if (grpname->name[0] == '*') {
8987836SJohn.Forte@Sun.COM 			ret = EINVAL;
8997836SJohn.Forte@Sun.COM 			break; /* not allowed */
9007836SJohn.Forte@Sun.COM 		}
9017836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9027836SJohn.Forte@Sun.COM 		ret = stmf_remove_group(grpname->name,
9037836SJohn.Forte@Sun.COM 		    grpname->name_size, idtype, &iocd->stmf_error);
9047836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9057836SJohn.Forte@Sun.COM 		break;
9067836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_VIEW_ENTRY:
9077836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
9087836SJohn.Forte@Sun.COM 			ret = EACCES;
9097836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
9107836SJohn.Forte@Sun.COM 			break;
9117836SJohn.Forte@Sun.COM 		}
9127836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
9137836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9147836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
9157836SJohn.Forte@Sun.COM 			ret = EINVAL;
9167836SJohn.Forte@Sun.COM 			break;
9177836SJohn.Forte@Sun.COM 		}
9187836SJohn.Forte@Sun.COM 		if (!ve->ve_lu_number_valid)
9197836SJohn.Forte@Sun.COM 			ve->ve_lu_nbr[2] = 0xFF;
9207836SJohn.Forte@Sun.COM 		if (ve->ve_all_hosts) {
9217836SJohn.Forte@Sun.COM 			ve->ve_host_group.name[0] = '*';
9227836SJohn.Forte@Sun.COM 			ve->ve_host_group.name_size = 1;
9237836SJohn.Forte@Sun.COM 		}
9247836SJohn.Forte@Sun.COM 		if (ve->ve_all_targets) {
9257836SJohn.Forte@Sun.COM 			ve->ve_target_group.name[0] = '*';
9267836SJohn.Forte@Sun.COM 			ve->ve_target_group.name_size = 1;
9277836SJohn.Forte@Sun.COM 		}
9287836SJohn.Forte@Sun.COM 		if (ve->ve_ndx_valid)
9297836SJohn.Forte@Sun.COM 			veid = ve->ve_ndx;
9307836SJohn.Forte@Sun.COM 		else
9317836SJohn.Forte@Sun.COM 			veid = 0xffffffff;
9327836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9337836SJohn.Forte@Sun.COM 		ret = stmf_add_ve(ve->ve_host_group.name,
9347836SJohn.Forte@Sun.COM 		    ve->ve_host_group.name_size,
9357836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name,
9367836SJohn.Forte@Sun.COM 		    ve->ve_target_group.name_size,
9377836SJohn.Forte@Sun.COM 		    ve->ve_guid,
9387836SJohn.Forte@Sun.COM 		    &veid,
9397836SJohn.Forte@Sun.COM 		    ve->ve_lu_nbr,
9407836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
9417836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9427836SJohn.Forte@Sun.COM 		if (ret == 0 &&
9437836SJohn.Forte@Sun.COM 		    (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) &&
9447836SJohn.Forte@Sun.COM 		    iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) {
9457836SJohn.Forte@Sun.COM 			stmf_view_op_entry_t *ve_ret =
9467836SJohn.Forte@Sun.COM 			    (stmf_view_op_entry_t *)obuf;
9477836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = 1;
9487836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = 1;
9497836SJohn.Forte@Sun.COM 			if (!ve->ve_ndx_valid) {
9507836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx = veid;
9517836SJohn.Forte@Sun.COM 				ve_ret->ve_ndx_valid = 1;
9527836SJohn.Forte@Sun.COM 			}
9537836SJohn.Forte@Sun.COM 			if (!ve->ve_lu_number_valid) {
9547836SJohn.Forte@Sun.COM 				ve_ret->ve_lu_number_valid = 1;
9557836SJohn.Forte@Sun.COM 				bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8);
9567836SJohn.Forte@Sun.COM 			}
9577836SJohn.Forte@Sun.COM 		}
9587836SJohn.Forte@Sun.COM 		break;
9597836SJohn.Forte@Sun.COM 	case STMF_IOCTL_REMOVE_VIEW_ENTRY:
9607836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
9617836SJohn.Forte@Sun.COM 			ret = EACCES;
9627836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
9637836SJohn.Forte@Sun.COM 			break;
9647836SJohn.Forte@Sun.COM 		}
9657836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)ibuf;
9667836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
9677836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
9687836SJohn.Forte@Sun.COM 			ret = EINVAL;
9697836SJohn.Forte@Sun.COM 			break;
9707836SJohn.Forte@Sun.COM 		}
9717836SJohn.Forte@Sun.COM 		if (!ve->ve_ndx_valid) {
9727836SJohn.Forte@Sun.COM 			ret = EINVAL;
9737836SJohn.Forte@Sun.COM 			break;
9747836SJohn.Forte@Sun.COM 		}
9757836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9767836SJohn.Forte@Sun.COM 		ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx,
9777836SJohn.Forte@Sun.COM 		    &iocd->stmf_error);
9787836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
9797836SJohn.Forte@Sun.COM 		break;
9807836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_LIST:
9817836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
9827836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
9837836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_LIST:
9847836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_LIST)
9857836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
9867836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
9877836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_max_nentries = id_list->id_count;
9887836SJohn.Forte@Sun.COM 		n = min(id_list->id_count,
9897836SJohn.Forte@Sun.COM 		    (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t));
9907836SJohn.Forte@Sun.COM 		iocd->stmf_obuf_nentries = n;
9917836SJohn.Forte@Sun.COM 		id_entry = id_list->idl_head;
9927836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)obuf;
9937836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
994*9585STim.Szeto@Sun.COM 			if (id_entry->id_data[0] == '*') {
995*9585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries > 0) {
996*9585STim.Szeto@Sun.COM 					iocd->stmf_obuf_nentries--;
997*9585STim.Szeto@Sun.COM 				}
998*9585STim.Szeto@Sun.COM 				id_entry = id_entry->id_next;
999*9585STim.Szeto@Sun.COM 				continue;
1000*9585STim.Szeto@Sun.COM 			}
1001*9585STim.Szeto@Sun.COM 			grpname->name_size = id_entry->id_data_size;
1002*9585STim.Szeto@Sun.COM 			bcopy(id_entry->id_data, grpname->name,
10037836SJohn.Forte@Sun.COM 			    id_entry->id_data_size);
1004*9585STim.Szeto@Sun.COM 			grpname++;
10057836SJohn.Forte@Sun.COM 			id_entry = id_entry->id_next;
10067836SJohn.Forte@Sun.COM 		}
10077836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10087836SJohn.Forte@Sun.COM 		break;
10097836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_HG_ENTRIES:
10107836SJohn.Forte@Sun.COM 		id_list = &stmf_state.stmf_hg_list;
10117836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
10127836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TG_ENTRIES:
10137836SJohn.Forte@Sun.COM 		grpname = (stmf_group_name_t *)ibuf;
10147836SJohn.Forte@Sun.COM 		if ((ibuf == NULL) ||
10157836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
10167836SJohn.Forte@Sun.COM 			ret = EINVAL;
10177836SJohn.Forte@Sun.COM 			break;
10187836SJohn.Forte@Sun.COM 		}
10197836SJohn.Forte@Sun.COM 		if (cmd == STMF_IOCTL_GET_TG_ENTRIES) {
10207836SJohn.Forte@Sun.COM 			id_list = &stmf_state.stmf_tg_list;
10217836SJohn.Forte@Sun.COM 		}
10227836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
10237836SJohn.Forte@Sun.COM 		id_entry = stmf_lookup_id(id_list, grpname->name_size,
10247836SJohn.Forte@Sun.COM 		    grpname->name);
10257836SJohn.Forte@Sun.COM 		if (!id_entry)
10267836SJohn.Forte@Sun.COM 			ret = ENODEV;
10277836SJohn.Forte@Sun.COM 		else {
10287836SJohn.Forte@Sun.COM 			stmf_ge_ident_t *grp_entry;
10297836SJohn.Forte@Sun.COM 			id_list = (stmf_id_list_t *)id_entry->id_impl_specific;
10307836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_max_nentries = id_list->id_count;
10317836SJohn.Forte@Sun.COM 			n = min(id_list->id_count,
10327836SJohn.Forte@Sun.COM 			    iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t));
10337836SJohn.Forte@Sun.COM 			iocd->stmf_obuf_nentries = n;
10347836SJohn.Forte@Sun.COM 			id_entry = id_list->idl_head;
10357836SJohn.Forte@Sun.COM 			grp_entry = (stmf_ge_ident_t *)obuf;
10367836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
1037*9585STim.Szeto@Sun.COM 				bcopy(id_entry->id_data, grp_entry->ident,
10387836SJohn.Forte@Sun.COM 				    id_entry->id_data_size);
1039*9585STim.Szeto@Sun.COM 				grp_entry->ident_size = id_entry->id_data_size;
10407836SJohn.Forte@Sun.COM 				id_entry = id_entry->id_next;
1041*9585STim.Szeto@Sun.COM 				grp_entry++;
10427836SJohn.Forte@Sun.COM 			}
10437836SJohn.Forte@Sun.COM 		}
10447836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10457836SJohn.Forte@Sun.COM 		break;
1046*9585STim.Szeto@Sun.COM 
10477836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_VE_LIST:
10487836SJohn.Forte@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
10497836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
10507836SJohn.Forte@Sun.COM 		ve = (stmf_view_op_entry_t *)obuf;
1051*9585STim.Szeto@Sun.COM 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
1052*9585STim.Szeto@Sun.COM 		    id_entry; id_entry = id_entry->id_next) {
1053*9585STim.Szeto@Sun.COM 			for (view_entry = (stmf_view_entry_t *)
1054*9585STim.Szeto@Sun.COM 			    id_entry->id_impl_specific; view_entry;
1055*9585STim.Szeto@Sun.COM 			    view_entry = view_entry->ve_next) {
1056*9585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
1057*9585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries >= n)
1058*9585STim.Szeto@Sun.COM 					continue;
10597836SJohn.Forte@Sun.COM 				ve->ve_ndx_valid = 1;
10607836SJohn.Forte@Sun.COM 				ve->ve_ndx = view_entry->ve_id;
10617836SJohn.Forte@Sun.COM 				ve->ve_lu_number_valid = 1;
10627836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
10637836SJohn.Forte@Sun.COM 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
10647836SJohn.Forte@Sun.COM 				    view_entry->ve_luid->id_data_size);
1065*9585STim.Szeto@Sun.COM 				if (view_entry->ve_hg->id_data[0] == '*') {
10667836SJohn.Forte@Sun.COM 					ve->ve_all_hosts = 1;
1067*9585STim.Szeto@Sun.COM 				} else {
10687836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_hg->id_data,
10697836SJohn.Forte@Sun.COM 					    ve->ve_host_group.name,
10707836SJohn.Forte@Sun.COM 					    view_entry->ve_hg->id_data_size);
1071*9585STim.Szeto@Sun.COM 					ve->ve_host_group.name_size =
1072*9585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size;
1073*9585STim.Szeto@Sun.COM 				}
1074*9585STim.Szeto@Sun.COM 
1075*9585STim.Szeto@Sun.COM 				if (view_entry->ve_tg->id_data[0] == '*') {
10767836SJohn.Forte@Sun.COM 					ve->ve_all_targets = 1;
1077*9585STim.Szeto@Sun.COM 				} else {
10787836SJohn.Forte@Sun.COM 					bcopy(view_entry->ve_tg->id_data,
10797836SJohn.Forte@Sun.COM 					    ve->ve_target_group.name,
10807836SJohn.Forte@Sun.COM 					    view_entry->ve_tg->id_data_size);
1081*9585STim.Szeto@Sun.COM 					ve->ve_target_group.name_size =
1082*9585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size;
1083*9585STim.Szeto@Sun.COM 				}
1084*9585STim.Szeto@Sun.COM 				ve++;
10857836SJohn.Forte@Sun.COM 				iocd->stmf_obuf_nentries++;
10867836SJohn.Forte@Sun.COM 			}
10877836SJohn.Forte@Sun.COM 		}
10887836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
10897836SJohn.Forte@Sun.COM 		break;
1090*9585STim.Szeto@Sun.COM 
1091*9585STim.Szeto@Sun.COM 	case STMF_IOCTL_LU_VE_LIST:
1092*9585STim.Szeto@Sun.COM 		p_id = (uint8_t *)ibuf;
1093*9585STim.Szeto@Sun.COM 		if ((iocd->stmf_ibuf_size != 16) ||
1094*9585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) {
1095*9585STim.Szeto@Sun.COM 			ret = EINVAL;
1096*9585STim.Szeto@Sun.COM 			break;
1097*9585STim.Szeto@Sun.COM 		}
1098*9585STim.Szeto@Sun.COM 
1099*9585STim.Szeto@Sun.COM 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
1100*9585STim.Szeto@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
1101*9585STim.Szeto@Sun.COM 		ve = (stmf_view_op_entry_t *)obuf;
1102*9585STim.Szeto@Sun.COM 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
1103*9585STim.Szeto@Sun.COM 		    id_entry; id_entry = id_entry->id_next) {
1104*9585STim.Szeto@Sun.COM 			if (bcmp(id_entry->id_data, p_id, 16) != 0)
1105*9585STim.Szeto@Sun.COM 				continue;
1106*9585STim.Szeto@Sun.COM 			for (view_entry = (stmf_view_entry_t *)
1107*9585STim.Szeto@Sun.COM 			    id_entry->id_impl_specific; view_entry;
1108*9585STim.Szeto@Sun.COM 			    view_entry = view_entry->ve_next) {
1109*9585STim.Szeto@Sun.COM 				iocd->stmf_obuf_max_nentries++;
1110*9585STim.Szeto@Sun.COM 				if (iocd->stmf_obuf_nentries >= n)
1111*9585STim.Szeto@Sun.COM 					continue;
1112*9585STim.Szeto@Sun.COM 				ve->ve_ndx_valid = 1;
1113*9585STim.Szeto@Sun.COM 				ve->ve_ndx = view_entry->ve_id;
1114*9585STim.Szeto@Sun.COM 				ve->ve_lu_number_valid = 1;
1115*9585STim.Szeto@Sun.COM 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
1116*9585STim.Szeto@Sun.COM 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
1117*9585STim.Szeto@Sun.COM 				    view_entry->ve_luid->id_data_size);
1118*9585STim.Szeto@Sun.COM 				if (view_entry->ve_hg->id_data[0] == '*') {
1119*9585STim.Szeto@Sun.COM 					ve->ve_all_hosts = 1;
1120*9585STim.Szeto@Sun.COM 				} else {
1121*9585STim.Szeto@Sun.COM 					bcopy(view_entry->ve_hg->id_data,
1122*9585STim.Szeto@Sun.COM 					    ve->ve_host_group.name,
1123*9585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size);
1124*9585STim.Szeto@Sun.COM 					ve->ve_host_group.name_size =
1125*9585STim.Szeto@Sun.COM 					    view_entry->ve_hg->id_data_size;
1126*9585STim.Szeto@Sun.COM 				}
1127*9585STim.Szeto@Sun.COM 
1128*9585STim.Szeto@Sun.COM 				if (view_entry->ve_tg->id_data[0] == '*') {
1129*9585STim.Szeto@Sun.COM 					ve->ve_all_targets = 1;
1130*9585STim.Szeto@Sun.COM 				} else {
1131*9585STim.Szeto@Sun.COM 					bcopy(view_entry->ve_tg->id_data,
1132*9585STim.Szeto@Sun.COM 					    ve->ve_target_group.name,
1133*9585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size);
1134*9585STim.Szeto@Sun.COM 					ve->ve_target_group.name_size =
1135*9585STim.Szeto@Sun.COM 					    view_entry->ve_tg->id_data_size;
1136*9585STim.Szeto@Sun.COM 				}
1137*9585STim.Szeto@Sun.COM 				ve++;
1138*9585STim.Szeto@Sun.COM 				iocd->stmf_obuf_nentries++;
1139*9585STim.Szeto@Sun.COM 			}
1140*9585STim.Szeto@Sun.COM 			break;
1141*9585STim.Szeto@Sun.COM 		}
1142*9585STim.Szeto@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
1143*9585STim.Szeto@Sun.COM 		break;
1144*9585STim.Szeto@Sun.COM 
11457836SJohn.Forte@Sun.COM 	case STMF_IOCTL_LOAD_PP_DATA:
11467836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
11477836SJohn.Forte@Sun.COM 			ret = EACCES;
11487836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
11497836SJohn.Forte@Sun.COM 			break;
11507836SJohn.Forte@Sun.COM 		}
11517836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
11527836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
11537836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
11547836SJohn.Forte@Sun.COM 			ret = EINVAL;
11557836SJohn.Forte@Sun.COM 			break;
11567836SJohn.Forte@Sun.COM 		}
1157*9585STim.Szeto@Sun.COM 		/* returned token */
1158*9585STim.Szeto@Sun.COM 		ppi_token = (uint64_t *)obuf;
1159*9585STim.Szeto@Sun.COM 		if ((ppi_token == NULL) ||
1160*9585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (uint64_t))) {
1161*9585STim.Szeto@Sun.COM 			ret = EINVAL;
1162*9585STim.Szeto@Sun.COM 			break;
1163*9585STim.Szeto@Sun.COM 		}
1164*9585STim.Szeto@Sun.COM 		ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error);
1165*9585STim.Szeto@Sun.COM 		break;
1166*9585STim.Szeto@Sun.COM 
1167*9585STim.Szeto@Sun.COM 	case STMF_IOCTL_GET_PP_DATA:
1168*9585STim.Szeto@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1169*9585STim.Szeto@Sun.COM 			ret = EACCES;
1170*9585STim.Szeto@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1171*9585STim.Szeto@Sun.COM 			break;
1172*9585STim.Szeto@Sun.COM 		}
1173*9585STim.Szeto@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
1174*9585STim.Szeto@Sun.COM 		if (ppi == NULL ||
1175*9585STim.Szeto@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1176*9585STim.Szeto@Sun.COM 			ret = EINVAL;
1177*9585STim.Szeto@Sun.COM 			break;
1178*9585STim.Szeto@Sun.COM 		}
1179*9585STim.Szeto@Sun.COM 		ppi_out = (stmf_ppioctl_data_t *)obuf;
1180*9585STim.Szeto@Sun.COM 		if ((ppi_out == NULL) ||
1181*9585STim.Szeto@Sun.COM 		    (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) {
1182*9585STim.Szeto@Sun.COM 			ret = EINVAL;
1183*9585STim.Szeto@Sun.COM 			break;
1184*9585STim.Szeto@Sun.COM 		}
1185*9585STim.Szeto@Sun.COM 		ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error);
11867836SJohn.Forte@Sun.COM 		break;
11877836SJohn.Forte@Sun.COM 
11887836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_PP_DATA:
11897836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
11907836SJohn.Forte@Sun.COM 			ret = EACCES;
11917836SJohn.Forte@Sun.COM 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
11927836SJohn.Forte@Sun.COM 			break;
11937836SJohn.Forte@Sun.COM 		}
11947836SJohn.Forte@Sun.COM 		ppi = (stmf_ppioctl_data_t *)ibuf;
11957836SJohn.Forte@Sun.COM 		if ((ppi == NULL) ||
11967836SJohn.Forte@Sun.COM 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
11977836SJohn.Forte@Sun.COM 			ret = EINVAL;
11987836SJohn.Forte@Sun.COM 			break;
11997836SJohn.Forte@Sun.COM 		}
12007836SJohn.Forte@Sun.COM 		ret = stmf_delete_ppd_ioctl(ppi);
12017836SJohn.Forte@Sun.COM 		break;
12027836SJohn.Forte@Sun.COM 
12037836SJohn.Forte@Sun.COM 	case STMF_IOCTL_CLEAR_TRACE:
12047836SJohn.Forte@Sun.COM 		stmf_trace_clear();
12057836SJohn.Forte@Sun.COM 		break;
12067836SJohn.Forte@Sun.COM 
12077836SJohn.Forte@Sun.COM 	case STMF_IOCTL_ADD_TRACE:
12087836SJohn.Forte@Sun.COM 		if (iocd->stmf_ibuf_size && ibuf) {
12097836SJohn.Forte@Sun.COM 			((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0;
12107836SJohn.Forte@Sun.COM 			stmf_trace("\nstradm", "%s\n", ibuf);
12117836SJohn.Forte@Sun.COM 		}
12127836SJohn.Forte@Sun.COM 		break;
12137836SJohn.Forte@Sun.COM 
12147836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE_POSITION:
12157836SJohn.Forte@Sun.COM 		if (obuf && (iocd->stmf_obuf_size > 3)) {
12167836SJohn.Forte@Sun.COM 			mutex_enter(&trace_buf_lock);
12177836SJohn.Forte@Sun.COM 			*((int *)obuf) = trace_buf_curndx;
12187836SJohn.Forte@Sun.COM 			mutex_exit(&trace_buf_lock);
12197836SJohn.Forte@Sun.COM 		} else {
12207836SJohn.Forte@Sun.COM 			ret = EINVAL;
12217836SJohn.Forte@Sun.COM 		}
12227836SJohn.Forte@Sun.COM 		break;
12237836SJohn.Forte@Sun.COM 
12247836SJohn.Forte@Sun.COM 	case STMF_IOCTL_GET_TRACE:
12257836SJohn.Forte@Sun.COM 		if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) {
12267836SJohn.Forte@Sun.COM 			ret = EINVAL;
12277836SJohn.Forte@Sun.COM 			break;
12287836SJohn.Forte@Sun.COM 		}
12297836SJohn.Forte@Sun.COM 		i = *((int *)ibuf);
12307836SJohn.Forte@Sun.COM 		if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) >
12317836SJohn.Forte@Sun.COM 		    trace_buf_size)) {
12327836SJohn.Forte@Sun.COM 			ret = EINVAL;
12337836SJohn.Forte@Sun.COM 			break;
12347836SJohn.Forte@Sun.COM 		}
12357836SJohn.Forte@Sun.COM 		mutex_enter(&trace_buf_lock);
12367836SJohn.Forte@Sun.COM 		bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size);
12377836SJohn.Forte@Sun.COM 		mutex_exit(&trace_buf_lock);
12387836SJohn.Forte@Sun.COM 		break;
12397836SJohn.Forte@Sun.COM 
12407836SJohn.Forte@Sun.COM 	default:
12417836SJohn.Forte@Sun.COM 		ret = ENOTTY;
12427836SJohn.Forte@Sun.COM 	}
12437836SJohn.Forte@Sun.COM 
12447836SJohn.Forte@Sun.COM 	if (ret == 0) {
12457836SJohn.Forte@Sun.COM 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
12467836SJohn.Forte@Sun.COM 	} else if (iocd->stmf_error) {
12477836SJohn.Forte@Sun.COM 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
12487836SJohn.Forte@Sun.COM 	}
12497836SJohn.Forte@Sun.COM 	if (obuf) {
12507836SJohn.Forte@Sun.COM 		kmem_free(obuf, iocd->stmf_obuf_size);
12517836SJohn.Forte@Sun.COM 		obuf = NULL;
12527836SJohn.Forte@Sun.COM 	}
12537836SJohn.Forte@Sun.COM 	if (ibuf) {
12547836SJohn.Forte@Sun.COM 		kmem_free(ibuf, iocd->stmf_ibuf_size);
12557836SJohn.Forte@Sun.COM 		ibuf = NULL;
12567836SJohn.Forte@Sun.COM 	}
12577836SJohn.Forte@Sun.COM 	kmem_free(iocd, sizeof (stmf_iocdata_t));
12587836SJohn.Forte@Sun.COM 	return (ret);
12597836SJohn.Forte@Sun.COM }
12607836SJohn.Forte@Sun.COM 
12617836SJohn.Forte@Sun.COM static int
12627836SJohn.Forte@Sun.COM stmf_get_service_state()
12637836SJohn.Forte@Sun.COM {
12647836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
12657836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
12667836SJohn.Forte@Sun.COM 	int online = 0;
12677836SJohn.Forte@Sun.COM 	int offline = 0;
12687836SJohn.Forte@Sun.COM 	int onlining = 0;
12697836SJohn.Forte@Sun.COM 	int offlining = 0;
12707836SJohn.Forte@Sun.COM 
12717836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
12727836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
12737836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
12747836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE)
12757836SJohn.Forte@Sun.COM 			offline++;
12767836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINE)
12777836SJohn.Forte@Sun.COM 			online++;
12787836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_ONLINING)
12797836SJohn.Forte@Sun.COM 			onlining++;
12807836SJohn.Forte@Sun.COM 		else if (ilport->ilport_state == STMF_STATE_OFFLINING)
12817836SJohn.Forte@Sun.COM 			offlining++;
12827836SJohn.Forte@Sun.COM 	}
12837836SJohn.Forte@Sun.COM 
12847836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
12857836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
12867836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE)
12877836SJohn.Forte@Sun.COM 			offline++;
12887836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINE)
12897836SJohn.Forte@Sun.COM 			online++;
12907836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_ONLINING)
12917836SJohn.Forte@Sun.COM 			onlining++;
12927836SJohn.Forte@Sun.COM 		else if (ilu->ilu_state == STMF_STATE_OFFLINING)
12937836SJohn.Forte@Sun.COM 			offlining++;
12947836SJohn.Forte@Sun.COM 	}
12957836SJohn.Forte@Sun.COM 
12967836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
12977836SJohn.Forte@Sun.COM 		if (onlining)
12987836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINING);
12997836SJohn.Forte@Sun.COM 		else
13007836SJohn.Forte@Sun.COM 			return (STMF_STATE_ONLINE);
13017836SJohn.Forte@Sun.COM 	}
13027836SJohn.Forte@Sun.COM 
13037836SJohn.Forte@Sun.COM 	if (offlining) {
13047836SJohn.Forte@Sun.COM 		return (STMF_STATE_OFFLINING);
13057836SJohn.Forte@Sun.COM 	}
13067836SJohn.Forte@Sun.COM 
13077836SJohn.Forte@Sun.COM 	return (STMF_STATE_OFFLINE);
13087836SJohn.Forte@Sun.COM }
13097836SJohn.Forte@Sun.COM 
13107836SJohn.Forte@Sun.COM static int
13117836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std)
13127836SJohn.Forte@Sun.COM {
13137836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
13147836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
13157836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssi;
13167836SJohn.Forte@Sun.COM 	int svc_state;
13177836SJohn.Forte@Sun.COM 
13187836SJohn.Forte@Sun.COM 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
13197836SJohn.Forte@Sun.COM 	ssi.st_additional_info = NULL;
13207836SJohn.Forte@Sun.COM 
13217836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
13227836SJohn.Forte@Sun.COM 	if (!stmf_state.stmf_exclusive_open) {
13237836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13247836SJohn.Forte@Sun.COM 		return (EACCES);
13257836SJohn.Forte@Sun.COM 	}
13267836SJohn.Forte@Sun.COM 
13277836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
13287836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13297836SJohn.Forte@Sun.COM 		return (EBUSY);
13307836SJohn.Forte@Sun.COM 	}
13317836SJohn.Forte@Sun.COM 
13327836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_ONLINE) &&
13337836SJohn.Forte@Sun.COM 	    (std->state != STMF_STATE_OFFLINE)) {
13347836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13357836SJohn.Forte@Sun.COM 		return (EINVAL);
13367836SJohn.Forte@Sun.COM 	}
13377836SJohn.Forte@Sun.COM 
13387836SJohn.Forte@Sun.COM 	svc_state = stmf_get_service_state();
13397836SJohn.Forte@Sun.COM 	if ((svc_state == STMF_STATE_OFFLINING) ||
13407836SJohn.Forte@Sun.COM 	    (svc_state == STMF_STATE_ONLINING)) {
13417836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13427836SJohn.Forte@Sun.COM 		return (EBUSY);
13437836SJohn.Forte@Sun.COM 	}
13447836SJohn.Forte@Sun.COM 
13457836SJohn.Forte@Sun.COM 	if (svc_state == STMF_STATE_OFFLINE) {
13467836SJohn.Forte@Sun.COM 		if (std->config_state == STMF_CONFIG_INIT) {
13477836SJohn.Forte@Sun.COM 			if (std->state != STMF_STATE_OFFLINE) {
13487836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
13497836SJohn.Forte@Sun.COM 				return (EINVAL);
13507836SJohn.Forte@Sun.COM 			}
13517836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT;
13527836SJohn.Forte@Sun.COM 			stmf_delete_all_ppds();
13537836SJohn.Forte@Sun.COM 			stmf_view_clear_config();
13547836SJohn.Forte@Sun.COM 			stmf_view_init();
13557836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13567836SJohn.Forte@Sun.COM 			return (0);
13577836SJohn.Forte@Sun.COM 		}
13587836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
13597836SJohn.Forte@Sun.COM 			if (std->config_state != STMF_CONFIG_INIT_DONE) {
13607836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
13617836SJohn.Forte@Sun.COM 				return (EINVAL);
13627836SJohn.Forte@Sun.COM 			}
13637836SJohn.Forte@Sun.COM 			stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE;
13647836SJohn.Forte@Sun.COM 		}
13657836SJohn.Forte@Sun.COM 		if (std->state == STMF_STATE_OFFLINE) {
13667836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13677836SJohn.Forte@Sun.COM 			return (0);
13687836SJohn.Forte@Sun.COM 		}
13697836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
13707836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
13717836SJohn.Forte@Sun.COM 			return (EINVAL);
13727836SJohn.Forte@Sun.COM 		}
13737836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 1;
13747836SJohn.Forte@Sun.COM 		stmf_state.stmf_service_running = 1;
13757836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13767836SJohn.Forte@Sun.COM 
13777836SJohn.Forte@Sun.COM 		for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
13787836SJohn.Forte@Sun.COM 		    ilport = ilport->ilport_next) {
13797836SJohn.Forte@Sun.COM 			if (ilport->ilport_prev_state != STMF_STATE_ONLINE)
13807836SJohn.Forte@Sun.COM 				continue;
13817836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE,
13828662SJordan.Vaughan@Sun.com 			    ilport->ilport_lport, &ssi);
13837836SJohn.Forte@Sun.COM 		}
13847836SJohn.Forte@Sun.COM 
13857836SJohn.Forte@Sun.COM 		for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
13867836SJohn.Forte@Sun.COM 		    ilu = ilu->ilu_next) {
13877836SJohn.Forte@Sun.COM 			if (ilu->ilu_prev_state != STMF_STATE_ONLINE)
13887836SJohn.Forte@Sun.COM 				continue;
13897836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi);
13907836SJohn.Forte@Sun.COM 		}
13917836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
13927836SJohn.Forte@Sun.COM 		stmf_state.stmf_inventory_locked = 0;
13937836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
13947836SJohn.Forte@Sun.COM 		return (0);
13957836SJohn.Forte@Sun.COM 	}
13967836SJohn.Forte@Sun.COM 
13977836SJohn.Forte@Sun.COM 	/* svc_state is STMF_STATE_ONLINE here */
13987836SJohn.Forte@Sun.COM 	if ((std->state != STMF_STATE_OFFLINE) ||
13997836SJohn.Forte@Sun.COM 	    (std->config_state == STMF_CONFIG_INIT)) {
14007836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
14017836SJohn.Forte@Sun.COM 		return (EACCES);
14027836SJohn.Forte@Sun.COM 	}
14037836SJohn.Forte@Sun.COM 
14047836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 1;
14057836SJohn.Forte@Sun.COM 	stmf_state.stmf_service_running = 0;
14067836SJohn.Forte@Sun.COM 	stmf_delete_all_ppds();
14077836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14087836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
14097836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
14107836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE)
14117836SJohn.Forte@Sun.COM 			continue;
14127836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE,
14137836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, &ssi);
14147836SJohn.Forte@Sun.COM 	}
14157836SJohn.Forte@Sun.COM 
14167836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
14177836SJohn.Forte@Sun.COM 	    ilu = ilu->ilu_next) {
14187836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE)
14197836SJohn.Forte@Sun.COM 			continue;
14207836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi);
14217836SJohn.Forte@Sun.COM 	}
14227836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14237836SJohn.Forte@Sun.COM 	stmf_state.stmf_inventory_locked = 0;
14247836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14257836SJohn.Forte@Sun.COM 	return (0);
14267836SJohn.Forte@Sun.COM }
14277836SJohn.Forte@Sun.COM 
14287836SJohn.Forte@Sun.COM static int
14297836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std)
14307836SJohn.Forte@Sun.COM {
14317836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
14327836SJohn.Forte@Sun.COM 	std->state = stmf_get_service_state();
14337836SJohn.Forte@Sun.COM 	std->config_state = stmf_state.stmf_config_state;
14347836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
14357836SJohn.Forte@Sun.COM 
14367836SJohn.Forte@Sun.COM 	return (0);
14377836SJohn.Forte@Sun.COM }
14387836SJohn.Forte@Sun.COM 
14397836SJohn.Forte@Sun.COM typedef struct {
14407836SJohn.Forte@Sun.COM 	void	*bp;	/* back pointer from internal struct to main struct */
14417836SJohn.Forte@Sun.COM 	int	alloc_size;
14427836SJohn.Forte@Sun.COM } __istmf_t;
14437836SJohn.Forte@Sun.COM 
14447836SJohn.Forte@Sun.COM typedef struct {
14457836SJohn.Forte@Sun.COM 	__istmf_t	*fp;	/* Framework private */
14467836SJohn.Forte@Sun.COM 	void		*cp;	/* Caller private */
14477836SJohn.Forte@Sun.COM 	void		*ss;	/* struct specific */
14487836SJohn.Forte@Sun.COM } __stmf_t;
14497836SJohn.Forte@Sun.COM 
14507836SJohn.Forte@Sun.COM static struct {
14517836SJohn.Forte@Sun.COM 	int shared;
14527836SJohn.Forte@Sun.COM 	int fw_private;
14537836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 },
14547836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_provider_t),
14557836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_provider_t) },
14567836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_port_provider_t),
14577836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_port_provider_t) },
14587836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_local_port_t),
14597836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_local_port_t) },
14607836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_lu_t),
14617836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_lu_t) },
14627836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_scsi_session_t),
14637836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_session_t) },
14647836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(scsi_task_t),
14657836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(stmf_i_scsi_task_t) },
14667836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_data_buf_t),
14677836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) },
14687836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(stmf_dbuf_store_t),
14697836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__istmf_t) }
14707836SJohn.Forte@Sun.COM 
14717836SJohn.Forte@Sun.COM };
14727836SJohn.Forte@Sun.COM 
14737836SJohn.Forte@Sun.COM void *
14747836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
14757836SJohn.Forte@Sun.COM {
14767836SJohn.Forte@Sun.COM 	int stmf_size;
14777836SJohn.Forte@Sun.COM 	int kmem_flag;
14787836SJohn.Forte@Sun.COM 	__stmf_t *sh;
14797836SJohn.Forte@Sun.COM 
14807836SJohn.Forte@Sun.COM 	if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS))
14817836SJohn.Forte@Sun.COM 		return (NULL);
14827836SJohn.Forte@Sun.COM 
14837836SJohn.Forte@Sun.COM 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
14847836SJohn.Forte@Sun.COM 		kmem_flag = KM_NOSLEEP;
14857836SJohn.Forte@Sun.COM 	} else {
14867836SJohn.Forte@Sun.COM 		kmem_flag = KM_SLEEP;
14877836SJohn.Forte@Sun.COM 	}
14887836SJohn.Forte@Sun.COM 
14897836SJohn.Forte@Sun.COM 	additional_size = (additional_size + 7) & (~7);
14907836SJohn.Forte@Sun.COM 	stmf_size = stmf_sizes[struct_id].shared +
14918662SJordan.Vaughan@Sun.com 	    stmf_sizes[struct_id].fw_private + additional_size;
14927836SJohn.Forte@Sun.COM 
14937836SJohn.Forte@Sun.COM 	sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag);
14947836SJohn.Forte@Sun.COM 
14957836SJohn.Forte@Sun.COM 	if (sh == NULL)
14967836SJohn.Forte@Sun.COM 		return (NULL);
14977836SJohn.Forte@Sun.COM 
14989087SZhong.Wang@Sun.COM 	/*
14999087SZhong.Wang@Sun.COM 	 * In principle, the implementation inside stmf_alloc should not
15009087SZhong.Wang@Sun.COM 	 * be changed anyway. But the original order of framework private
15019087SZhong.Wang@Sun.COM 	 * data and caller private data does not support sglist in the caller
15029087SZhong.Wang@Sun.COM 	 * private data.
15039087SZhong.Wang@Sun.COM 	 * To work around this, the memory segments of framework private
15049087SZhong.Wang@Sun.COM 	 * data and caller private data are re-ordered here.
15059087SZhong.Wang@Sun.COM 	 * A better solution is to provide a specific interface to allocate
15069087SZhong.Wang@Sun.COM 	 * the sglist, then we will not need this workaround any more.
15079087SZhong.Wang@Sun.COM 	 * But before the new interface is available, the memory segment
15089087SZhong.Wang@Sun.COM 	 * ordering should be kept as is.
15099087SZhong.Wang@Sun.COM 	 */
15109087SZhong.Wang@Sun.COM 	sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
15119087SZhong.Wang@Sun.COM 	sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh,
15129087SZhong.Wang@Sun.COM 	    stmf_sizes[struct_id].shared + additional_size);
15137836SJohn.Forte@Sun.COM 
15147836SJohn.Forte@Sun.COM 	sh->fp->bp = sh;
15157836SJohn.Forte@Sun.COM 	/* Just store the total size instead of storing additional size */
15167836SJohn.Forte@Sun.COM 	sh->fp->alloc_size = stmf_size;
15177836SJohn.Forte@Sun.COM 
15187836SJohn.Forte@Sun.COM 	return (sh);
15197836SJohn.Forte@Sun.COM }
15207836SJohn.Forte@Sun.COM 
15217836SJohn.Forte@Sun.COM void
15227836SJohn.Forte@Sun.COM stmf_free(void *ptr)
15237836SJohn.Forte@Sun.COM {
15247836SJohn.Forte@Sun.COM 	__stmf_t *sh = (__stmf_t *)ptr;
15257836SJohn.Forte@Sun.COM 
15267836SJohn.Forte@Sun.COM 	/*
15277836SJohn.Forte@Sun.COM 	 * So far we dont need any struct specific processing. If such
15287836SJohn.Forte@Sun.COM 	 * a need ever arises, then store the struct id in the framework
15297836SJohn.Forte@Sun.COM 	 * private section and get it here as sh->fp->struct_id.
15307836SJohn.Forte@Sun.COM 	 */
15317836SJohn.Forte@Sun.COM 	kmem_free(ptr, sh->fp->alloc_size);
15327836SJohn.Forte@Sun.COM }
15337836SJohn.Forte@Sun.COM 
15347836SJohn.Forte@Sun.COM /*
15357836SJohn.Forte@Sun.COM  * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
15367836SJohn.Forte@Sun.COM  * framework and returns a pointer to framework private data for the lu.
15377836SJohn.Forte@Sun.COM  * Returns NULL if the lu was not found.
15387836SJohn.Forte@Sun.COM  */
15397836SJohn.Forte@Sun.COM stmf_i_lu_t *
15407836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu)
15417836SJohn.Forte@Sun.COM {
15427836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
15437836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
15447836SJohn.Forte@Sun.COM 
15457836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
15467836SJohn.Forte@Sun.COM 		if (ilu->ilu_lu == lu)
15477836SJohn.Forte@Sun.COM 			return (ilu);
15487836SJohn.Forte@Sun.COM 	}
15497836SJohn.Forte@Sun.COM 	return (NULL);
15507836SJohn.Forte@Sun.COM }
15517836SJohn.Forte@Sun.COM 
15527836SJohn.Forte@Sun.COM /*
15538818STim.Szeto@Sun.COM  * Given a pointer to stmf_local_port_t, verifies if this lport is registered
15548818STim.Szeto@Sun.COM  * with the framework and returns a pointer to framework private data for
15558818STim.Szeto@Sun.COM  * the lport.
15568818STim.Szeto@Sun.COM  * Returns NULL if the lport was not found.
15577836SJohn.Forte@Sun.COM  */
15587836SJohn.Forte@Sun.COM stmf_i_local_port_t *
15597836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport)
15607836SJohn.Forte@Sun.COM {
15617836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
15627836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
15637836SJohn.Forte@Sun.COM 
15647836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
15657836SJohn.Forte@Sun.COM 	    ilport = ilport->ilport_next) {
15667836SJohn.Forte@Sun.COM 		if (ilport->ilport_lport == lport)
15677836SJohn.Forte@Sun.COM 			return (ilport);
15687836SJohn.Forte@Sun.COM 	}
15697836SJohn.Forte@Sun.COM 	return (NULL);
15707836SJohn.Forte@Sun.COM }
15717836SJohn.Forte@Sun.COM 
15727836SJohn.Forte@Sun.COM stmf_status_t
15737836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp)
15747836SJohn.Forte@Sun.COM {
15757836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
15767836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
15777836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
15787836SJohn.Forte@Sun.COM 
15797836SJohn.Forte@Sun.COM 	if (lp->lp_lpif_rev != LPIF_REV_1)
15807836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
15817836SJohn.Forte@Sun.COM 
15827836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
15837836SJohn.Forte@Sun.COM 	ilp->ilp_next = stmf_state.stmf_ilplist;
15847836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilplist = ilp;
15857836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlps++;
15867836SJohn.Forte@Sun.COM 
15877836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
15887836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
15897836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, lp->lp_name) == 0) {
15907836SJohn.Forte@Sun.COM 			break;
15917836SJohn.Forte@Sun.COM 		}
15927836SJohn.Forte@Sun.COM 	}
15937836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
15947836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
15957836SJohn.Forte@Sun.COM 	}
15967836SJohn.Forte@Sun.COM 	ilp->ilp_ppd = ppd;
15977836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ilp;
15987836SJohn.Forte@Sun.COM 	if (lp->lp_cb == NULL)
15997836SJohn.Forte@Sun.COM 		goto rlp_bail_out;
16007836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 1;
16017836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
16027836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
16037836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
16047836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16057836SJohn.Forte@Sun.COM 	lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
16067836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16077836SJohn.Forte@Sun.COM 	ilp->ilp_cb_in_progress = 0;
16087836SJohn.Forte@Sun.COM 
16097836SJohn.Forte@Sun.COM rlp_bail_out:
16107836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16117836SJohn.Forte@Sun.COM 
16127836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
16137836SJohn.Forte@Sun.COM }
16147836SJohn.Forte@Sun.COM 
16157836SJohn.Forte@Sun.COM stmf_status_t
16167836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp)
16177836SJohn.Forte@Sun.COM {
16187836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t	**ppilp;
16197836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
16207836SJohn.Forte@Sun.COM 
16217836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16227836SJohn.Forte@Sun.COM 	if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) {
16237836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
16247836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
16257836SJohn.Forte@Sun.COM 	}
16267836SJohn.Forte@Sun.COM 	for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL;
16277836SJohn.Forte@Sun.COM 	    ppilp = &((*ppilp)->ilp_next)) {
16287836SJohn.Forte@Sun.COM 		if (*ppilp == ilp) {
16297836SJohn.Forte@Sun.COM 			*ppilp = ilp->ilp_next;
16307836SJohn.Forte@Sun.COM 			stmf_state.stmf_nlps--;
16317836SJohn.Forte@Sun.COM 			if (ilp->ilp_ppd) {
16327836SJohn.Forte@Sun.COM 				ilp->ilp_ppd->ppd_provider = NULL;
16337836SJohn.Forte@Sun.COM 				ilp->ilp_ppd = NULL;
16347836SJohn.Forte@Sun.COM 			}
16357836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
16367836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
16377836SJohn.Forte@Sun.COM 		}
16387836SJohn.Forte@Sun.COM 	}
16397836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16407836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
16417836SJohn.Forte@Sun.COM }
16427836SJohn.Forte@Sun.COM 
16437836SJohn.Forte@Sun.COM stmf_status_t
16447836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp)
16457836SJohn.Forte@Sun.COM {
16467836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
16477836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
16487836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
16497836SJohn.Forte@Sun.COM 	uint32_t cb_flags;
16507836SJohn.Forte@Sun.COM 
16517836SJohn.Forte@Sun.COM 	if (pp->pp_portif_rev != PORTIF_REV_1)
16527836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
16537836SJohn.Forte@Sun.COM 
16547836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16557836SJohn.Forte@Sun.COM 	ipp->ipp_next = stmf_state.stmf_ipplist;
16567836SJohn.Forte@Sun.COM 	stmf_state.stmf_ipplist = ipp;
16577836SJohn.Forte@Sun.COM 	stmf_state.stmf_npps++;
16587836SJohn.Forte@Sun.COM 	/* See if we need to do a callback */
16597836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
16607836SJohn.Forte@Sun.COM 		if (strcmp(ppd->ppd_name, pp->pp_name) == 0) {
16617836SJohn.Forte@Sun.COM 			break;
16627836SJohn.Forte@Sun.COM 		}
16637836SJohn.Forte@Sun.COM 	}
16647836SJohn.Forte@Sun.COM 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
16657836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
16667836SJohn.Forte@Sun.COM 	}
16677836SJohn.Forte@Sun.COM 	ipp->ipp_ppd = ppd;
16687836SJohn.Forte@Sun.COM 	ppd->ppd_provider = ipp;
16697836SJohn.Forte@Sun.COM 	if (pp->pp_cb == NULL)
16707836SJohn.Forte@Sun.COM 		goto rpp_bail_out;
16717836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 1;
16727836SJohn.Forte@Sun.COM 	cb_flags = STMF_PCB_PREG_COMPLETE;
16737836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
16747836SJohn.Forte@Sun.COM 		cb_flags |= STMF_PCB_STMF_ONLINING;
16757836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16767836SJohn.Forte@Sun.COM 	pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
16777836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16787836SJohn.Forte@Sun.COM 	ipp->ipp_cb_in_progress = 0;
16797836SJohn.Forte@Sun.COM 
16807836SJohn.Forte@Sun.COM rpp_bail_out:
16817836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
16827836SJohn.Forte@Sun.COM 
16837836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
16847836SJohn.Forte@Sun.COM }
16857836SJohn.Forte@Sun.COM 
16867836SJohn.Forte@Sun.COM stmf_status_t
16877836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp)
16887836SJohn.Forte@Sun.COM {
16897836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t *ipp =
16907836SJohn.Forte@Sun.COM 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
16917836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t **ppipp;
16927836SJohn.Forte@Sun.COM 
16937836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
16947836SJohn.Forte@Sun.COM 	if (ipp->ipp_npps || ipp->ipp_cb_in_progress) {
16957836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
16967836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
16977836SJohn.Forte@Sun.COM 	}
16987836SJohn.Forte@Sun.COM 	for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL;
16997836SJohn.Forte@Sun.COM 	    ppipp = &((*ppipp)->ipp_next)) {
17007836SJohn.Forte@Sun.COM 		if (*ppipp == ipp) {
17017836SJohn.Forte@Sun.COM 			*ppipp = ipp->ipp_next;
17027836SJohn.Forte@Sun.COM 			stmf_state.stmf_npps--;
17037836SJohn.Forte@Sun.COM 			if (ipp->ipp_ppd) {
17047836SJohn.Forte@Sun.COM 				ipp->ipp_ppd->ppd_provider = NULL;
17057836SJohn.Forte@Sun.COM 				ipp->ipp_ppd = NULL;
17067836SJohn.Forte@Sun.COM 			}
17077836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17087836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
17097836SJohn.Forte@Sun.COM 		}
17107836SJohn.Forte@Sun.COM 	}
17117836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
17127836SJohn.Forte@Sun.COM 	return (STMF_NOT_FOUND);
17137836SJohn.Forte@Sun.COM }
17147836SJohn.Forte@Sun.COM 
17157836SJohn.Forte@Sun.COM int
1716*9585STim.Szeto@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
1717*9585STim.Szeto@Sun.COM     uint32_t *err_ret)
17187836SJohn.Forte@Sun.COM {
17197836SJohn.Forte@Sun.COM 	stmf_i_port_provider_t		*ipp;
17207836SJohn.Forte@Sun.COM 	stmf_i_lu_provider_t		*ilp;
17217836SJohn.Forte@Sun.COM 	stmf_pp_data_t			*ppd;
17227836SJohn.Forte@Sun.COM 	nvlist_t			*nv;
17237836SJohn.Forte@Sun.COM 	int				s;
17247836SJohn.Forte@Sun.COM 	int				ret;
17257836SJohn.Forte@Sun.COM 
1726*9585STim.Szeto@Sun.COM 	*err_ret = 0;
1727*9585STim.Szeto@Sun.COM 
17287836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
17297836SJohn.Forte@Sun.COM 		return (EINVAL);
17307836SJohn.Forte@Sun.COM 	}
17317836SJohn.Forte@Sun.COM 
17327836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
17337836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
17347836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
17357836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
17367836SJohn.Forte@Sun.COM 				continue;
17377836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
17387836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
17397836SJohn.Forte@Sun.COM 				continue;
17407836SJohn.Forte@Sun.COM 		}
17417836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
17427836SJohn.Forte@Sun.COM 			break;
17437836SJohn.Forte@Sun.COM 	}
17447836SJohn.Forte@Sun.COM 
17457836SJohn.Forte@Sun.COM 	if (ppd == NULL) {
17467836SJohn.Forte@Sun.COM 		/* New provider */
17477836SJohn.Forte@Sun.COM 		s = strlen(ppi->ppi_name);
17487836SJohn.Forte@Sun.COM 		if (s > 254) {
17497836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17507836SJohn.Forte@Sun.COM 			return (EINVAL);
17517836SJohn.Forte@Sun.COM 		}
17527836SJohn.Forte@Sun.COM 		s += sizeof (stmf_pp_data_t) - 7;
17537836SJohn.Forte@Sun.COM 
17547836SJohn.Forte@Sun.COM 		ppd = kmem_zalloc(s, KM_NOSLEEP);
17557836SJohn.Forte@Sun.COM 		if (ppd == NULL) {
17567836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
17577836SJohn.Forte@Sun.COM 			return (ENOMEM);
17587836SJohn.Forte@Sun.COM 		}
17597836SJohn.Forte@Sun.COM 		ppd->ppd_alloc_size = s;
17607836SJohn.Forte@Sun.COM 		(void) strcpy(ppd->ppd_name, ppi->ppi_name);
17617836SJohn.Forte@Sun.COM 
17627836SJohn.Forte@Sun.COM 		/* See if this provider already exists */
17637836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
17647836SJohn.Forte@Sun.COM 			ppd->ppd_lu_provider = 1;
17657836SJohn.Forte@Sun.COM 			for (ilp = stmf_state.stmf_ilplist; ilp != NULL;
17667836SJohn.Forte@Sun.COM 			    ilp = ilp->ilp_next) {
17677836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
17687836SJohn.Forte@Sun.COM 				    ilp->ilp_lp->lp_name) == 0) {
17697836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ilp;
17707836SJohn.Forte@Sun.COM 					ilp->ilp_ppd = ppd;
17717836SJohn.Forte@Sun.COM 					break;
17727836SJohn.Forte@Sun.COM 				}
17737836SJohn.Forte@Sun.COM 			}
17747836SJohn.Forte@Sun.COM 		} else {
17757836SJohn.Forte@Sun.COM 			ppd->ppd_port_provider = 1;
17767836SJohn.Forte@Sun.COM 			for (ipp = stmf_state.stmf_ipplist; ipp != NULL;
17777836SJohn.Forte@Sun.COM 			    ipp = ipp->ipp_next) {
17787836SJohn.Forte@Sun.COM 				if (strcmp(ppi->ppi_name,
17797836SJohn.Forte@Sun.COM 				    ipp->ipp_pp->pp_name) == 0) {
17807836SJohn.Forte@Sun.COM 					ppd->ppd_provider = ipp;
17817836SJohn.Forte@Sun.COM 					ipp->ipp_ppd = ppd;
17827836SJohn.Forte@Sun.COM 					break;
17837836SJohn.Forte@Sun.COM 				}
17847836SJohn.Forte@Sun.COM 			}
17857836SJohn.Forte@Sun.COM 		}
17867836SJohn.Forte@Sun.COM 
17877836SJohn.Forte@Sun.COM 		/* Link this ppd in */
17887836SJohn.Forte@Sun.COM 		ppd->ppd_next = stmf_state.stmf_ppdlist;
17897836SJohn.Forte@Sun.COM 		stmf_state.stmf_ppdlist = ppd;
17907836SJohn.Forte@Sun.COM 	}
17917836SJohn.Forte@Sun.COM 
1792*9585STim.Szeto@Sun.COM 	/*
1793*9585STim.Szeto@Sun.COM 	 * User is requesting that the token be checked.
1794*9585STim.Szeto@Sun.COM 	 * If there was another set after the user's get
1795*9585STim.Szeto@Sun.COM 	 * it's an error
1796*9585STim.Szeto@Sun.COM 	 */
1797*9585STim.Szeto@Sun.COM 	if (ppi->ppi_token_valid) {
1798*9585STim.Szeto@Sun.COM 		if (ppi->ppi_token != ppd->ppd_token) {
1799*9585STim.Szeto@Sun.COM 			*err_ret = STMF_IOCERR_PPD_UPDATED;
1800*9585STim.Szeto@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
1801*9585STim.Szeto@Sun.COM 			return (EINVAL);
1802*9585STim.Szeto@Sun.COM 		}
1803*9585STim.Szeto@Sun.COM 	}
1804*9585STim.Szeto@Sun.COM 
18057836SJohn.Forte@Sun.COM 	if ((ret = nvlist_unpack((char *)ppi->ppi_data,
18067836SJohn.Forte@Sun.COM 	    (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
18077836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
18087836SJohn.Forte@Sun.COM 		return (ret);
18097836SJohn.Forte@Sun.COM 	}
18107836SJohn.Forte@Sun.COM 
18117836SJohn.Forte@Sun.COM 	/* Free any existing lists and add this one to the ppd */
18127836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
18137836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
18147836SJohn.Forte@Sun.COM 	ppd->ppd_nv = nv;
18157836SJohn.Forte@Sun.COM 
1816*9585STim.Szeto@Sun.COM 	/* set the token for writes */
1817*9585STim.Szeto@Sun.COM 	ppd->ppd_token++;
1818*9585STim.Szeto@Sun.COM 	/* return token to caller */
1819*9585STim.Szeto@Sun.COM 	if (ppi_token) {
1820*9585STim.Szeto@Sun.COM 		*ppi_token = ppd->ppd_token;
1821*9585STim.Szeto@Sun.COM 	}
1822*9585STim.Szeto@Sun.COM 
18237836SJohn.Forte@Sun.COM 	/* If there is a provider registered, do the notifications */
18247836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
18257836SJohn.Forte@Sun.COM 		uint32_t cb_flags = 0;
18267836SJohn.Forte@Sun.COM 
18277836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
18287836SJohn.Forte@Sun.COM 			cb_flags |= STMF_PCB_STMF_ONLINING;
18297836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
18307836SJohn.Forte@Sun.COM 			ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider;
18317836SJohn.Forte@Sun.COM 			if (ilp->ilp_lp->lp_cb == NULL)
18327836SJohn.Forte@Sun.COM 				goto bail_out;
18337836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 1;
18347836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
18357836SJohn.Forte@Sun.COM 			ilp->ilp_lp->lp_cb(ilp->ilp_lp,
18367836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
18377836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
18387836SJohn.Forte@Sun.COM 			ilp->ilp_cb_in_progress = 0;
18397836SJohn.Forte@Sun.COM 		} else {
18407836SJohn.Forte@Sun.COM 			ipp = (stmf_i_port_provider_t *)ppd->ppd_provider;
18417836SJohn.Forte@Sun.COM 			if (ipp->ipp_pp->pp_cb == NULL)
18427836SJohn.Forte@Sun.COM 				goto bail_out;
18437836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 1;
18447836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
18457836SJohn.Forte@Sun.COM 			ipp->ipp_pp->pp_cb(ipp->ipp_pp,
18467836SJohn.Forte@Sun.COM 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
18477836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
18487836SJohn.Forte@Sun.COM 			ipp->ipp_cb_in_progress = 0;
18497836SJohn.Forte@Sun.COM 		}
18507836SJohn.Forte@Sun.COM 	}
18517836SJohn.Forte@Sun.COM 
18527836SJohn.Forte@Sun.COM bail_out:
18537836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
18547836SJohn.Forte@Sun.COM 
18557836SJohn.Forte@Sun.COM 	return (0);
18567836SJohn.Forte@Sun.COM }
18577836SJohn.Forte@Sun.COM 
18587836SJohn.Forte@Sun.COM void
18597836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd)
18607836SJohn.Forte@Sun.COM {
18617836SJohn.Forte@Sun.COM 	stmf_pp_data_t **pppd;
18627836SJohn.Forte@Sun.COM 
18637836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
18647836SJohn.Forte@Sun.COM 	if (ppd->ppd_provider) {
18657836SJohn.Forte@Sun.COM 		if (ppd->ppd_lu_provider) {
18667836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
18677836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ilp_ppd = NULL;
18687836SJohn.Forte@Sun.COM 		} else {
18697836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
18707836SJohn.Forte@Sun.COM 			    ppd->ppd_provider)->ipp_ppd = NULL;
18717836SJohn.Forte@Sun.COM 		}
18727836SJohn.Forte@Sun.COM 		ppd->ppd_provider = NULL;
18737836SJohn.Forte@Sun.COM 	}
18747836SJohn.Forte@Sun.COM 
18757836SJohn.Forte@Sun.COM 	for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL;
18768662SJordan.Vaughan@Sun.com 	    pppd = &((*pppd)->ppd_next)) {
18777836SJohn.Forte@Sun.COM 		if (*pppd == ppd)
18787836SJohn.Forte@Sun.COM 			break;
18797836SJohn.Forte@Sun.COM 	}
18807836SJohn.Forte@Sun.COM 
18817836SJohn.Forte@Sun.COM 	if (*pppd == NULL)
18827836SJohn.Forte@Sun.COM 		return;
18837836SJohn.Forte@Sun.COM 
18847836SJohn.Forte@Sun.COM 	*pppd = ppd->ppd_next;
18857836SJohn.Forte@Sun.COM 	if (ppd->ppd_nv)
18867836SJohn.Forte@Sun.COM 		nvlist_free(ppd->ppd_nv);
18877836SJohn.Forte@Sun.COM 
18887836SJohn.Forte@Sun.COM 	kmem_free(ppd, ppd->ppd_alloc_size);
18897836SJohn.Forte@Sun.COM }
18907836SJohn.Forte@Sun.COM 
18917836SJohn.Forte@Sun.COM int
18927836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
18937836SJohn.Forte@Sun.COM {
18947836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd;
18957836SJohn.Forte@Sun.COM 	int ret = ENOENT;
18967836SJohn.Forte@Sun.COM 
18977836SJohn.Forte@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
18987836SJohn.Forte@Sun.COM 		return (EINVAL);
18997836SJohn.Forte@Sun.COM 	}
19007836SJohn.Forte@Sun.COM 
19017836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
19027836SJohn.Forte@Sun.COM 
19037836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
19047836SJohn.Forte@Sun.COM 		if (ppi->ppi_lu_provider) {
19057836SJohn.Forte@Sun.COM 			if (!ppd->ppd_lu_provider)
19067836SJohn.Forte@Sun.COM 				continue;
19077836SJohn.Forte@Sun.COM 		} else if (ppi->ppi_port_provider) {
19087836SJohn.Forte@Sun.COM 			if (!ppd->ppd_port_provider)
19097836SJohn.Forte@Sun.COM 				continue;
19107836SJohn.Forte@Sun.COM 		}
19117836SJohn.Forte@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
19127836SJohn.Forte@Sun.COM 			break;
19137836SJohn.Forte@Sun.COM 	}
19147836SJohn.Forte@Sun.COM 
19157836SJohn.Forte@Sun.COM 	if (ppd) {
19167836SJohn.Forte@Sun.COM 		ret = 0;
19177836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
19187836SJohn.Forte@Sun.COM 	}
19197836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
19207836SJohn.Forte@Sun.COM 
19217836SJohn.Forte@Sun.COM 	return (ret);
19227836SJohn.Forte@Sun.COM }
19237836SJohn.Forte@Sun.COM 
1924*9585STim.Szeto@Sun.COM int
1925*9585STim.Szeto@Sun.COM stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
1926*9585STim.Szeto@Sun.COM     uint32_t *err_ret)
1927*9585STim.Szeto@Sun.COM {
1928*9585STim.Szeto@Sun.COM 	stmf_pp_data_t *ppd;
1929*9585STim.Szeto@Sun.COM 	size_t req_size;
1930*9585STim.Szeto@Sun.COM 	int ret = ENOENT;
1931*9585STim.Szeto@Sun.COM 	char *bufp = (char *)ppi_out->ppi_data;
1932*9585STim.Szeto@Sun.COM 
1933*9585STim.Szeto@Sun.COM 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
1934*9585STim.Szeto@Sun.COM 		return (EINVAL);
1935*9585STim.Szeto@Sun.COM 	}
1936*9585STim.Szeto@Sun.COM 
1937*9585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
1938*9585STim.Szeto@Sun.COM 
1939*9585STim.Szeto@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
1940*9585STim.Szeto@Sun.COM 		if (ppi->ppi_lu_provider) {
1941*9585STim.Szeto@Sun.COM 			if (!ppd->ppd_lu_provider)
1942*9585STim.Szeto@Sun.COM 				continue;
1943*9585STim.Szeto@Sun.COM 		} else if (ppi->ppi_port_provider) {
1944*9585STim.Szeto@Sun.COM 			if (!ppd->ppd_port_provider)
1945*9585STim.Szeto@Sun.COM 				continue;
1946*9585STim.Szeto@Sun.COM 		}
1947*9585STim.Szeto@Sun.COM 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
1948*9585STim.Szeto@Sun.COM 			break;
1949*9585STim.Szeto@Sun.COM 	}
1950*9585STim.Szeto@Sun.COM 
1951*9585STim.Szeto@Sun.COM 	if (ppd && ppd->ppd_nv) {
1952*9585STim.Szeto@Sun.COM 		ppi_out->ppi_token = ppd->ppd_token;
1953*9585STim.Szeto@Sun.COM 		if ((ret = nvlist_size(ppd->ppd_nv, &req_size,
1954*9585STim.Szeto@Sun.COM 		    NV_ENCODE_XDR)) != 0) {
1955*9585STim.Szeto@Sun.COM 			goto done;
1956*9585STim.Szeto@Sun.COM 		}
1957*9585STim.Szeto@Sun.COM 		ppi_out->ppi_data_size = req_size;
1958*9585STim.Szeto@Sun.COM 		if (req_size > ppi->ppi_data_size) {
1959*9585STim.Szeto@Sun.COM 			*err_ret = STMF_IOCERR_INSUFFICIENT_BUF;
1960*9585STim.Szeto@Sun.COM 			ret = EINVAL;
1961*9585STim.Szeto@Sun.COM 			goto done;
1962*9585STim.Szeto@Sun.COM 		}
1963*9585STim.Szeto@Sun.COM 
1964*9585STim.Szeto@Sun.COM 		if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size,
1965*9585STim.Szeto@Sun.COM 		    NV_ENCODE_XDR, 0)) != 0) {
1966*9585STim.Szeto@Sun.COM 			goto done;
1967*9585STim.Szeto@Sun.COM 		}
1968*9585STim.Szeto@Sun.COM 		ret = 0;
1969*9585STim.Szeto@Sun.COM 	}
1970*9585STim.Szeto@Sun.COM 
1971*9585STim.Szeto@Sun.COM done:
1972*9585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
1973*9585STim.Szeto@Sun.COM 
1974*9585STim.Szeto@Sun.COM 	return (ret);
1975*9585STim.Szeto@Sun.COM }
1976*9585STim.Szeto@Sun.COM 
19777836SJohn.Forte@Sun.COM void
19787836SJohn.Forte@Sun.COM stmf_delete_all_ppds()
19797836SJohn.Forte@Sun.COM {
19807836SJohn.Forte@Sun.COM 	stmf_pp_data_t *ppd, *nppd;
19817836SJohn.Forte@Sun.COM 
19827836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
19837836SJohn.Forte@Sun.COM 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) {
19847836SJohn.Forte@Sun.COM 		nppd = ppd->ppd_next;
19857836SJohn.Forte@Sun.COM 		stmf_delete_ppd(ppd);
19867836SJohn.Forte@Sun.COM 	}
19877836SJohn.Forte@Sun.COM }
19887836SJohn.Forte@Sun.COM 
19899435STim.Szeto@Sun.COM /*
19909435STim.Szeto@Sun.COM  * 16 is the max string length of a protocol_ident, increase
19919435STim.Szeto@Sun.COM  * the size if needed.
19929435STim.Szeto@Sun.COM  */
19939435STim.Szeto@Sun.COM #define	STMF_KSTAT_LU_SZ	(STMF_GUID_INPUT + 1 + 256)
19949435STim.Szeto@Sun.COM #define	STMF_KSTAT_TGT_SZ	(256 * 2 + 16)
19959435STim.Szeto@Sun.COM 
19969435STim.Szeto@Sun.COM typedef struct stmf_kstat_lu_info {
19979435STim.Szeto@Sun.COM 	kstat_named_t		i_lun_guid;
19989435STim.Szeto@Sun.COM 	kstat_named_t		i_lun_alias;
19999435STim.Szeto@Sun.COM } stmf_kstat_lu_info_t;
20009435STim.Szeto@Sun.COM 
20019435STim.Szeto@Sun.COM typedef struct stmf_kstat_tgt_info {
20029435STim.Szeto@Sun.COM 	kstat_named_t		i_tgt_name;
20039435STim.Szeto@Sun.COM 	kstat_named_t		i_tgt_alias;
20049435STim.Szeto@Sun.COM 	kstat_named_t		i_protocol;
20059435STim.Szeto@Sun.COM } stmf_kstat_tgt_info_t;
20069435STim.Szeto@Sun.COM 
20079435STim.Szeto@Sun.COM /*
20089435STim.Szeto@Sun.COM  * This array matches the Protocol Identifier in stmf_ioctl.h
20099435STim.Szeto@Sun.COM  */
20109435STim.Szeto@Sun.COM char *protocol_ident[PROTOCOL_ANY] = {
20119435STim.Szeto@Sun.COM 	"Fibre Channel",
20129435STim.Szeto@Sun.COM 	"Parallel SCSI",
20139435STim.Szeto@Sun.COM 	"SSA",
20149435STim.Szeto@Sun.COM 	"IEEE_1394",
20159435STim.Szeto@Sun.COM 	"SRP",
20169435STim.Szeto@Sun.COM 	"iSCSI",
20179435STim.Szeto@Sun.COM 	"SAS",
20189435STim.Szeto@Sun.COM 	"ADT",
20199435STim.Szeto@Sun.COM 	"ATAPI",
20209435STim.Szeto@Sun.COM 	"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"
20219435STim.Szeto@Sun.COM };
20229435STim.Szeto@Sun.COM 
20239435STim.Szeto@Sun.COM /*
20249435STim.Szeto@Sun.COM  * Update the lun wait/run queue count
20259435STim.Szeto@Sun.COM  */
20269435STim.Szeto@Sun.COM static void
20279435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(scsi_task_t *task, void func())
20289435STim.Szeto@Sun.COM {
20299435STim.Szeto@Sun.COM 	stmf_i_lu_t		*ilu;
20309435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20319435STim.Szeto@Sun.COM 
20329435STim.Szeto@Sun.COM 	if (task->task_lu == dlun0)
20339435STim.Szeto@Sun.COM 		return;
20349435STim.Szeto@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
20359435STim.Szeto@Sun.COM 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
20369435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
20379435STim.Szeto@Sun.COM 		if (kip != NULL) {
20389435STim.Szeto@Sun.COM 			mutex_enter(ilu->ilu_kstat_io->ks_lock);
20399435STim.Szeto@Sun.COM 			func(kip);
20409435STim.Szeto@Sun.COM 			mutex_exit(ilu->ilu_kstat_io->ks_lock);
20419435STim.Szeto@Sun.COM 		}
20429435STim.Szeto@Sun.COM 	}
20439435STim.Szeto@Sun.COM }
20449435STim.Szeto@Sun.COM 
20459435STim.Szeto@Sun.COM /*
20469435STim.Szeto@Sun.COM  * Update the target(lport) wait/run queue count
20479435STim.Szeto@Sun.COM  */
20489435STim.Szeto@Sun.COM static void
20499435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(scsi_task_t *task, void func())
20509435STim.Szeto@Sun.COM {
20519435STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilp;
20529435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20539435STim.Szeto@Sun.COM 
20549435STim.Szeto@Sun.COM 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
20559435STim.Szeto@Sun.COM 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
20569435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
20579435STim.Szeto@Sun.COM 		if (kip != NULL) {
20589435STim.Szeto@Sun.COM 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
20599435STim.Szeto@Sun.COM 			func(kip);
20609435STim.Szeto@Sun.COM 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
20619435STim.Szeto@Sun.COM 		}
20629435STim.Szeto@Sun.COM 	}
20639435STim.Szeto@Sun.COM }
20649435STim.Szeto@Sun.COM 
20659435STim.Szeto@Sun.COM static void
20669435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
20679435STim.Szeto@Sun.COM {
20689435STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilp;
20699435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20709435STim.Szeto@Sun.COM 
20719435STim.Szeto@Sun.COM 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
20729435STim.Szeto@Sun.COM 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
20739435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
20749435STim.Szeto@Sun.COM 		if (kip != NULL) {
20759435STim.Szeto@Sun.COM 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
20769435STim.Szeto@Sun.COM 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
20779435STim.Szeto@Sun.COM 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
20789435STim.Szeto@Sun.COM 		}
20799435STim.Szeto@Sun.COM 	}
20809435STim.Szeto@Sun.COM }
20819435STim.Szeto@Sun.COM 
20829435STim.Szeto@Sun.COM static void
20839435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
20849435STim.Szeto@Sun.COM {
20859435STim.Szeto@Sun.COM 	stmf_i_lu_t		*ilu;
20869435STim.Szeto@Sun.COM 	kstat_io_t		*kip;
20879435STim.Szeto@Sun.COM 
20889435STim.Szeto@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
20899435STim.Szeto@Sun.COM 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
20909435STim.Szeto@Sun.COM 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
20919435STim.Szeto@Sun.COM 		if (kip != NULL) {
20929435STim.Szeto@Sun.COM 			mutex_enter(ilu->ilu_kstat_io->ks_lock);
20939435STim.Szeto@Sun.COM 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
20949435STim.Szeto@Sun.COM 			mutex_exit(ilu->ilu_kstat_io->ks_lock);
20959435STim.Szeto@Sun.COM 		}
20969435STim.Szeto@Sun.COM 	}
20979435STim.Szeto@Sun.COM }
20989435STim.Szeto@Sun.COM 
20999435STim.Szeto@Sun.COM static void
21009435STim.Szeto@Sun.COM stmf_create_kstat_lu(stmf_i_lu_t *ilu)
21019435STim.Szeto@Sun.COM {
21029435STim.Szeto@Sun.COM 	char				ks_nm[KSTAT_STRLEN];
21039435STim.Szeto@Sun.COM 	stmf_kstat_lu_info_t		*ks_lu;
21049435STim.Szeto@Sun.COM 
21059435STim.Szeto@Sun.COM 	/* create kstat lun info */
21069435STim.Szeto@Sun.COM 	ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ,
21079435STim.Szeto@Sun.COM 	    KM_NOSLEEP);
21089435STim.Szeto@Sun.COM 	if (ks_lu == NULL) {
21099435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
21109435STim.Szeto@Sun.COM 		return;
21119435STim.Szeto@Sun.COM 	}
21129435STim.Szeto@Sun.COM 
21139435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21149435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu);
21159435STim.Szeto@Sun.COM 	if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0,
21169435STim.Szeto@Sun.COM 	    ks_nm, "misc", KSTAT_TYPE_NAMED,
21179435STim.Szeto@Sun.COM 	    sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t),
21189435STim.Szeto@Sun.COM 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
21199435STim.Szeto@Sun.COM 		kmem_free(ks_lu, STMF_KSTAT_LU_SZ);
21209435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create lu failed");
21219435STim.Szeto@Sun.COM 		return;
21229435STim.Szeto@Sun.COM 	}
21239435STim.Szeto@Sun.COM 
21249435STim.Szeto@Sun.COM 	ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ;
21259435STim.Szeto@Sun.COM 	ilu->ilu_kstat_info->ks_data = ks_lu;
21269435STim.Szeto@Sun.COM 
21279435STim.Szeto@Sun.COM 	kstat_named_init(&ks_lu->i_lun_guid, "lun-guid",
21289435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21299435STim.Szeto@Sun.COM 	kstat_named_init(&ks_lu->i_lun_alias, "lun-alias",
21309435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21319435STim.Szeto@Sun.COM 
21329435STim.Szeto@Sun.COM 	/* convert guid to hex string */
21339435STim.Szeto@Sun.COM 	int		i;
21349435STim.Szeto@Sun.COM 	uint8_t		*p = ilu->ilu_lu->lu_id->ident;
21359435STim.Szeto@Sun.COM 	bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid));
21369435STim.Szeto@Sun.COM 	for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
21379435STim.Szeto@Sun.COM 		(void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]);
21389435STim.Szeto@Sun.COM 	}
21399435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_lu->i_lun_guid,
21409435STim.Szeto@Sun.COM 	    (const char *)ilu->ilu_ascii_hex_guid);
21419435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_lu->i_lun_alias,
21429435STim.Szeto@Sun.COM 	    (const char *)ilu->ilu_lu->lu_alias);
21439435STim.Szeto@Sun.COM 	kstat_install(ilu->ilu_kstat_info);
21449435STim.Szeto@Sun.COM 
21459435STim.Szeto@Sun.COM 	/* create kstat lun io */
21469435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21479435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu);
21489435STim.Szeto@Sun.COM 	if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
21499435STim.Szeto@Sun.COM 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
21509435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create lu_io failed");
21519435STim.Szeto@Sun.COM 		return;
21529435STim.Szeto@Sun.COM 	}
21539435STim.Szeto@Sun.COM 	mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0);
21549435STim.Szeto@Sun.COM 	ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock;
21559435STim.Szeto@Sun.COM 	kstat_install(ilu->ilu_kstat_io);
21569435STim.Szeto@Sun.COM }
21579435STim.Szeto@Sun.COM 
21589435STim.Szeto@Sun.COM static void
21599435STim.Szeto@Sun.COM stmf_create_kstat_lport(stmf_i_local_port_t *ilport)
21609435STim.Szeto@Sun.COM {
21619435STim.Szeto@Sun.COM 	char				ks_nm[KSTAT_STRLEN];
21629435STim.Szeto@Sun.COM 	stmf_kstat_tgt_info_t		*ks_tgt;
21639435STim.Szeto@Sun.COM 	int				id, len;
21649435STim.Szeto@Sun.COM 
21659435STim.Szeto@Sun.COM 	/* create kstat lport info */
21669435STim.Szeto@Sun.COM 	ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ,
21679435STim.Szeto@Sun.COM 	    KM_NOSLEEP);
21689435STim.Szeto@Sun.COM 	if (ks_tgt == NULL) {
21699435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
21709435STim.Szeto@Sun.COM 		return;
21719435STim.Szeto@Sun.COM 	}
21729435STim.Szeto@Sun.COM 
21739435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
21749435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport);
21759435STim.Szeto@Sun.COM 	if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME,
21769435STim.Szeto@Sun.COM 	    0, ks_nm, "misc", KSTAT_TYPE_NAMED,
21779435STim.Szeto@Sun.COM 	    sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t),
21789435STim.Szeto@Sun.COM 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
21799435STim.Szeto@Sun.COM 		kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ);
21809435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create target failed");
21819435STim.Szeto@Sun.COM 		return;
21829435STim.Szeto@Sun.COM 	}
21839435STim.Szeto@Sun.COM 
21849435STim.Szeto@Sun.COM 	ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ;
21859435STim.Szeto@Sun.COM 	ilport->ilport_kstat_info->ks_data = ks_tgt;
21869435STim.Szeto@Sun.COM 
21879435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_tgt_name, "target-name",
21889435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21899435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias",
21909435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21919435STim.Szeto@Sun.COM 	kstat_named_init(&ks_tgt->i_protocol, "protocol",
21929435STim.Szeto@Sun.COM 	    KSTAT_DATA_STRING);
21939435STim.Szeto@Sun.COM 
21949435STim.Szeto@Sun.COM 	/* ident might not be null terminated */
21959435STim.Szeto@Sun.COM 	len = ilport->ilport_lport->lport_id->ident_length;
21969435STim.Szeto@Sun.COM 	bcopy(ilport->ilport_lport->lport_id->ident,
21979435STim.Szeto@Sun.COM 	    ilport->ilport_kstat_tgt_name, len);
21989435STim.Szeto@Sun.COM 	ilport->ilport_kstat_tgt_name[len + 1] = NULL;
21999435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_tgt_name,
22009435STim.Szeto@Sun.COM 	    (const char *)ilport->ilport_kstat_tgt_name);
22019435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_tgt_alias,
22029435STim.Szeto@Sun.COM 	    (const char *)ilport->ilport_lport->lport_alias);
22039435STim.Szeto@Sun.COM 	/* protocol */
22049435STim.Szeto@Sun.COM 	if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) {
22059435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: protocol_id out of bound");
22069435STim.Szeto@Sun.COM 		id = PROTOCOL_ANY;
22079435STim.Szeto@Sun.COM 	}
22089435STim.Szeto@Sun.COM 	kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]);
22099435STim.Szeto@Sun.COM 	kstat_install(ilport->ilport_kstat_info);
22109435STim.Szeto@Sun.COM 
22119435STim.Szeto@Sun.COM 	/* create kstat lport io */
22129435STim.Szeto@Sun.COM 	bzero(ks_nm, sizeof (ks_nm));
22139435STim.Szeto@Sun.COM 	(void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport);
22149435STim.Szeto@Sun.COM 	if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
22159435STim.Szeto@Sun.COM 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
22169435STim.Szeto@Sun.COM 		cmn_err(CE_WARN, "STMF: kstat_create target_io failed");
22179435STim.Szeto@Sun.COM 		return;
22189435STim.Szeto@Sun.COM 	}
22199435STim.Szeto@Sun.COM 	mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0);
22209435STim.Szeto@Sun.COM 	ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock;
22219435STim.Szeto@Sun.COM 	kstat_install(ilport->ilport_kstat_io);
22229435STim.Szeto@Sun.COM }
22239435STim.Szeto@Sun.COM 
22247836SJohn.Forte@Sun.COM stmf_status_t
22257836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu)
22267836SJohn.Forte@Sun.COM {
22277836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
22287836SJohn.Forte@Sun.COM 	uint8_t *p1, *p2;
22297836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
22307836SJohn.Forte@Sun.COM 	stmf_id_data_t *luid;
22317836SJohn.Forte@Sun.COM 
22327836SJohn.Forte@Sun.COM 	if ((lu->lu_id->ident_type != ID_TYPE_NAA) ||
22337836SJohn.Forte@Sun.COM 	    (lu->lu_id->ident_length != 16) ||
22347836SJohn.Forte@Sun.COM 	    ((lu->lu_id->ident[0] & 0xf0) != 0x60)) {
22357836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
22367836SJohn.Forte@Sun.COM 	}
22377836SJohn.Forte@Sun.COM 	p1 = &lu->lu_id->ident[0];
22387836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
22397836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
22407836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
22417836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
22427836SJohn.Forte@Sun.COM 	}
22437836SJohn.Forte@Sun.COM 
22447836SJohn.Forte@Sun.COM 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
22457836SJohn.Forte@Sun.COM 		p2 = &ilu->ilu_lu->lu_id->ident[0];
22467836SJohn.Forte@Sun.COM 		if (bcmp(p1, p2, 16) == 0) {
22477836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
22487836SJohn.Forte@Sun.COM 			return (STMF_ALREADY);
22497836SJohn.Forte@Sun.COM 		}
22507836SJohn.Forte@Sun.COM 	}
22517836SJohn.Forte@Sun.COM 
22527836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
22537836SJohn.Forte@Sun.COM 	luid = stmf_lookup_id(&stmf_state.stmf_luid_list,
22547836SJohn.Forte@Sun.COM 	    lu->lu_id->ident_length, lu->lu_id->ident);
22557836SJohn.Forte@Sun.COM 	if (luid) {
22567836SJohn.Forte@Sun.COM 		luid->id_pt_to_object = (void *)ilu;
22577836SJohn.Forte@Sun.COM 		ilu->ilu_luid = luid;
22587836SJohn.Forte@Sun.COM 	}
22597836SJohn.Forte@Sun.COM 	ilu->ilu_alias = NULL;
22607836SJohn.Forte@Sun.COM 
22617836SJohn.Forte@Sun.COM 	ilu->ilu_next = stmf_state.stmf_ilulist;
22627836SJohn.Forte@Sun.COM 	ilu->ilu_prev = NULL;
22637836SJohn.Forte@Sun.COM 	if (ilu->ilu_next)
22647836SJohn.Forte@Sun.COM 		ilu->ilu_next->ilu_prev = ilu;
22657836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilulist = ilu;
22667836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlus++;
22677836SJohn.Forte@Sun.COM 	if (lu->lu_lp) {
22687836SJohn.Forte@Sun.COM 		((stmf_i_lu_provider_t *)
22697836SJohn.Forte@Sun.COM 		    (lu->lu_lp->lp_stmf_private))->ilp_nlus++;
22707836SJohn.Forte@Sun.COM 	}
22717836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
22727836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
22739435STim.Szeto@Sun.COM 	stmf_create_kstat_lu(ilu);
22747836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
22757836SJohn.Forte@Sun.COM 
22767836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lu can be brought online */
22777836SJohn.Forte@Sun.COM 	ilu->ilu_prev_state = STMF_STATE_ONLINE;
22787836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
22797836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
22807836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
22817836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci);
22827836SJohn.Forte@Sun.COM 	}
22837836SJohn.Forte@Sun.COM 
22847836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
22857836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
22867836SJohn.Forte@Sun.COM }
22877836SJohn.Forte@Sun.COM 
22887836SJohn.Forte@Sun.COM stmf_status_t
22897836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu)
22907836SJohn.Forte@Sun.COM {
22917836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
22927836SJohn.Forte@Sun.COM 
22937836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
22947836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
22957836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
22967836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
22977836SJohn.Forte@Sun.COM 	}
22987836SJohn.Forte@Sun.COM 	ilu = stmf_lookup_lu(lu);
22997836SJohn.Forte@Sun.COM 	if (ilu == NULL) {
23007836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
23017836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
23027836SJohn.Forte@Sun.COM 	}
23037836SJohn.Forte@Sun.COM 	if (ilu->ilu_state == STMF_STATE_OFFLINE) {
23047836SJohn.Forte@Sun.COM 		ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
23057836SJohn.Forte@Sun.COM 		while (ilu->ilu_flags & ILU_STALL_DEREGISTER) {
23067836SJohn.Forte@Sun.COM 			cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock);
23077836SJohn.Forte@Sun.COM 		}
23087836SJohn.Forte@Sun.COM 		if (ilu->ilu_ntasks) {
23097836SJohn.Forte@Sun.COM 			stmf_i_scsi_task_t *itask, *nitask;
23107836SJohn.Forte@Sun.COM 
23117836SJohn.Forte@Sun.COM 			nitask = ilu->ilu_tasks;
23127836SJohn.Forte@Sun.COM 			do {
23137836SJohn.Forte@Sun.COM 				itask = nitask;
23147836SJohn.Forte@Sun.COM 				nitask = itask->itask_lu_next;
23157836SJohn.Forte@Sun.COM 				lu->lu_task_free(itask->itask_task);
23167836SJohn.Forte@Sun.COM 				stmf_free(itask->itask_task);
23177836SJohn.Forte@Sun.COM 			} while (nitask != NULL);
23187836SJohn.Forte@Sun.COM 
23197836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = ilu->ilu_free_tasks = NULL;
23207836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0;
23217836SJohn.Forte@Sun.COM 		}
23227836SJohn.Forte@Sun.COM 
23237836SJohn.Forte@Sun.COM 		if (ilu->ilu_next)
23247836SJohn.Forte@Sun.COM 			ilu->ilu_next->ilu_prev = ilu->ilu_prev;
23257836SJohn.Forte@Sun.COM 		if (ilu->ilu_prev)
23267836SJohn.Forte@Sun.COM 			ilu->ilu_prev->ilu_next = ilu->ilu_next;
23277836SJohn.Forte@Sun.COM 		else
23287836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilulist = ilu->ilu_next;
23297836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlus--;
23307836SJohn.Forte@Sun.COM 
23317836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_draining) {
23327836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
23337836SJohn.Forte@Sun.COM 		}
23347836SJohn.Forte@Sun.COM 		if (ilu == stmf_state.stmf_svc_ilu_timing) {
23357836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
23367836SJohn.Forte@Sun.COM 		}
23377836SJohn.Forte@Sun.COM 		if (lu->lu_lp) {
23387836SJohn.Forte@Sun.COM 			((stmf_i_lu_provider_t *)
23397836SJohn.Forte@Sun.COM 			    (lu->lu_lp->lp_stmf_private))->ilp_nlus--;
23407836SJohn.Forte@Sun.COM 		}
23417836SJohn.Forte@Sun.COM 		if (ilu->ilu_luid) {
23427836SJohn.Forte@Sun.COM 			((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object =
23437836SJohn.Forte@Sun.COM 			    NULL;
23447836SJohn.Forte@Sun.COM 			ilu->ilu_luid = NULL;
23457836SJohn.Forte@Sun.COM 		}
23467836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl);
23477836SJohn.Forte@Sun.COM 	} else {
23487836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
23497836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
23507836SJohn.Forte@Sun.COM 	}
23519435STim.Szeto@Sun.COM 	if (ilu->ilu_kstat_info) {
23529435STim.Szeto@Sun.COM 		kstat_delete(ilu->ilu_kstat_info);
23539435STim.Szeto@Sun.COM 	}
23549435STim.Szeto@Sun.COM 	if (ilu->ilu_kstat_io) {
23559435STim.Szeto@Sun.COM 		kstat_delete(ilu->ilu_kstat_io);
23569435STim.Szeto@Sun.COM 		mutex_destroy(&ilu->ilu_kstat_lock);
23579435STim.Szeto@Sun.COM 	}
23587836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
23597836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
23607836SJohn.Forte@Sun.COM }
23617836SJohn.Forte@Sun.COM 
23627836SJohn.Forte@Sun.COM stmf_status_t
23637836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport)
23647836SJohn.Forte@Sun.COM {
23657836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
23667836SJohn.Forte@Sun.COM 	stmf_state_change_info_t ssci;
23677836SJohn.Forte@Sun.COM 	int start_workers = 0;
23687836SJohn.Forte@Sun.COM 
23697836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
23707836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
23717836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
23727836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
23737836SJohn.Forte@Sun.COM 	}
23747836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
23757836SJohn.Forte@Sun.COM 	rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL);
23767836SJohn.Forte@Sun.COM 
23777836SJohn.Forte@Sun.COM 	ilport->ilport_next = stmf_state.stmf_ilportlist;
23787836SJohn.Forte@Sun.COM 	ilport->ilport_prev = NULL;
23797836SJohn.Forte@Sun.COM 	if (ilport->ilport_next)
23807836SJohn.Forte@Sun.COM 		ilport->ilport_next->ilport_prev = ilport;
23817836SJohn.Forte@Sun.COM 	stmf_state.stmf_ilportlist = ilport;
23827836SJohn.Forte@Sun.COM 	stmf_state.stmf_nlports++;
23837836SJohn.Forte@Sun.COM 	if (lport->lport_pp) {
23847836SJohn.Forte@Sun.COM 		((stmf_i_port_provider_t *)
23857836SJohn.Forte@Sun.COM 		    (lport->lport_pp->pp_stmf_private))->ipp_npps++;
23867836SJohn.Forte@Sun.COM 	}
23877836SJohn.Forte@Sun.COM 	ilport->ilport_tg =
23887836SJohn.Forte@Sun.COM 	    stmf_lookup_group_for_target(lport->lport_id->ident,
23898662SJordan.Vaughan@Sun.com 	    lport->lport_id->ident_length);
23907836SJohn.Forte@Sun.COM 	ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1);
23917836SJohn.Forte@Sun.COM 	STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl);
23929435STim.Szeto@Sun.COM 	stmf_create_kstat_lport(ilport);
23937836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED) {
23947836SJohn.Forte@Sun.COM 		stmf_workers_state = STMF_WORKERS_ENABLING;
23957836SJohn.Forte@Sun.COM 		start_workers = 1;
23967836SJohn.Forte@Sun.COM 	}
23977836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
23987836SJohn.Forte@Sun.COM 
23997836SJohn.Forte@Sun.COM 	if (start_workers)
24007836SJohn.Forte@Sun.COM 		stmf_worker_init();
24017836SJohn.Forte@Sun.COM 
24027836SJohn.Forte@Sun.COM 	/* XXX we should probably check if this lport can be brought online */
24037836SJohn.Forte@Sun.COM 	ilport->ilport_prev_state = STMF_STATE_ONLINE;
24047836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_service_running) {
24057836SJohn.Forte@Sun.COM 		ssci.st_rflags = 0;
24067836SJohn.Forte@Sun.COM 		ssci.st_additional_info = NULL;
24077836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci);
24087836SJohn.Forte@Sun.COM 	}
24097836SJohn.Forte@Sun.COM 
24107836SJohn.Forte@Sun.COM 	/* XXX: Generate event */
24117836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
24127836SJohn.Forte@Sun.COM }
24137836SJohn.Forte@Sun.COM 
24147836SJohn.Forte@Sun.COM stmf_status_t
24157836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport)
24167836SJohn.Forte@Sun.COM {
24177836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
24187836SJohn.Forte@Sun.COM 
24197836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
24207836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_inventory_locked) {
24217836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
24227836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
24237836SJohn.Forte@Sun.COM 	}
24247836SJohn.Forte@Sun.COM 	ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
24257836SJohn.Forte@Sun.COM 	if (ilport->ilport_nsessions == 0) {
24267836SJohn.Forte@Sun.COM 		if (ilport->ilport_next)
24277836SJohn.Forte@Sun.COM 			ilport->ilport_next->ilport_prev = ilport->ilport_prev;
24287836SJohn.Forte@Sun.COM 		if (ilport->ilport_prev)
24297836SJohn.Forte@Sun.COM 			ilport->ilport_prev->ilport_next = ilport->ilport_next;
24307836SJohn.Forte@Sun.COM 		else
24317836SJohn.Forte@Sun.COM 			stmf_state.stmf_ilportlist = ilport->ilport_next;
24327836SJohn.Forte@Sun.COM 		rw_destroy(&ilport->ilport_lock);
24337836SJohn.Forte@Sun.COM 		stmf_state.stmf_nlports--;
24347836SJohn.Forte@Sun.COM 		if (lport->lport_pp) {
24357836SJohn.Forte@Sun.COM 			((stmf_i_port_provider_t *)
24367836SJohn.Forte@Sun.COM 			    (lport->lport_pp->pp_stmf_private))->ipp_npps--;
24377836SJohn.Forte@Sun.COM 		}
24387836SJohn.Forte@Sun.COM 		ilport->ilport_tg = NULL;
24397836SJohn.Forte@Sun.COM 		STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl);
24407836SJohn.Forte@Sun.COM 	} else {
24417836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
24427836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
24437836SJohn.Forte@Sun.COM 	}
24449435STim.Szeto@Sun.COM 	if (ilport->ilport_kstat_info) {
24459435STim.Szeto@Sun.COM 		kstat_delete(ilport->ilport_kstat_info);
24469435STim.Szeto@Sun.COM 	}
24479435STim.Szeto@Sun.COM 	if (ilport->ilport_kstat_io) {
24489435STim.Szeto@Sun.COM 		kstat_delete(ilport->ilport_kstat_io);
24499435STim.Szeto@Sun.COM 		mutex_destroy(&ilport->ilport_kstat_lock);
24509435STim.Szeto@Sun.COM 	}
24517836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
24527836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
24537836SJohn.Forte@Sun.COM }
24547836SJohn.Forte@Sun.COM 
24557836SJohn.Forte@Sun.COM /*
24567836SJohn.Forte@Sun.COM  * Port provider has to make sure that register/deregister session and
24577836SJohn.Forte@Sun.COM  * port are serialized calls.
24587836SJohn.Forte@Sun.COM  */
24597836SJohn.Forte@Sun.COM stmf_status_t
24607836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
24617836SJohn.Forte@Sun.COM {
24627836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
24637836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
24647836SJohn.Forte@Sun.COM 	    lport->lport_stmf_private;
24657836SJohn.Forte@Sun.COM 	uint8_t		lun[8];
24667836SJohn.Forte@Sun.COM 
24677836SJohn.Forte@Sun.COM 	/*
24687836SJohn.Forte@Sun.COM 	 * Port state has to be online to register a scsi session. It is
24697836SJohn.Forte@Sun.COM 	 * possible that we started an offline operation and a new SCSI
24707836SJohn.Forte@Sun.COM 	 * session started at the same time (in that case also we are going
24717836SJohn.Forte@Sun.COM 	 * to fail the registeration). But any other state is simply
24727836SJohn.Forte@Sun.COM 	 * a bad port provider implementation.
24737836SJohn.Forte@Sun.COM 	 */
24747836SJohn.Forte@Sun.COM 	if (ilport->ilport_state != STMF_STATE_ONLINE) {
24757836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
24767836SJohn.Forte@Sun.COM 			stmf_trace(lport->lport_alias, "Port is trying to "
24777836SJohn.Forte@Sun.COM 			    "register a session while the state is neither "
24787836SJohn.Forte@Sun.COM 			    "online nor offlining");
24797836SJohn.Forte@Sun.COM 		}
24807836SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
24817836SJohn.Forte@Sun.COM 	}
24827836SJohn.Forte@Sun.COM 	bzero(lun, 8);
24837836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
24847836SJohn.Forte@Sun.COM 	iss->iss_flags |= ISS_BEING_CREATED;
24857836SJohn.Forte@Sun.COM 
24867836SJohn.Forte@Sun.COM 	/* sessions use the ilport_lock. No separate lock is required */
24877836SJohn.Forte@Sun.COM 	iss->iss_lockp = &ilport->ilport_lock;
24887836SJohn.Forte@Sun.COM 	(void) stmf_session_create_lun_map(ilport, iss);
24897836SJohn.Forte@Sun.COM 
24907836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
24917836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions++;
24927836SJohn.Forte@Sun.COM 	iss->iss_next = ilport->ilport_ss_list;
24937836SJohn.Forte@Sun.COM 	ilport->ilport_ss_list = iss;
24947836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
24957836SJohn.Forte@Sun.COM 
24967836SJohn.Forte@Sun.COM 	iss->iss_creation_time = ddi_get_time();
24977836SJohn.Forte@Sun.COM 	ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1);
24987836SJohn.Forte@Sun.COM 	iss->iss_flags &= ~ISS_BEING_CREATED;
24998859STim.Szeto@Sun.COM 	DTRACE_PROBE2(session__online, stmf_local_port_t *, lport,
25008859STim.Szeto@Sun.COM 	    stmf_scsi_session_t *, ss);
25017836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
25027836SJohn.Forte@Sun.COM }
25037836SJohn.Forte@Sun.COM 
25047836SJohn.Forte@Sun.COM void
25057836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
25067836SJohn.Forte@Sun.COM {
25077836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
25088662SJordan.Vaughan@Sun.com 	    lport->lport_stmf_private;
25097836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss, **ppss;
25107836SJohn.Forte@Sun.COM 	int found = 0;
25117836SJohn.Forte@Sun.COM 
25128859STim.Szeto@Sun.COM 	DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport,
25138859STim.Szeto@Sun.COM 	    stmf_scsi_session_t *, ss);
25148859STim.Szeto@Sun.COM 
25157836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
25167836SJohn.Forte@Sun.COM 	if (ss->ss_rport_alias) {
25177836SJohn.Forte@Sun.COM 		ss->ss_rport_alias = NULL;
25187836SJohn.Forte@Sun.COM 	}
25197836SJohn.Forte@Sun.COM 
25207836SJohn.Forte@Sun.COM try_dereg_ss_again:
25217836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
25227836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
25238662SJordan.Vaughan@Sun.com 	    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
25247836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_EVENT_ACTIVE) {
25257836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
25267836SJohn.Forte@Sun.COM 		delay(1);
25277836SJohn.Forte@Sun.COM 		goto try_dereg_ss_again;
25287836SJohn.Forte@Sun.COM 	}
25297836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
25307836SJohn.Forte@Sun.COM 	rw_enter(&ilport->ilport_lock, RW_WRITER);
25317836SJohn.Forte@Sun.COM 	for (ppss = &ilport->ilport_ss_list; *ppss != NULL;
25327836SJohn.Forte@Sun.COM 	    ppss = &((*ppss)->iss_next)) {
25337836SJohn.Forte@Sun.COM 		if (iss == (*ppss)) {
25347836SJohn.Forte@Sun.COM 			*ppss = (*ppss)->iss_next;
25357836SJohn.Forte@Sun.COM 			found = 1;
25367836SJohn.Forte@Sun.COM 			break;
25377836SJohn.Forte@Sun.COM 		}
25387836SJohn.Forte@Sun.COM 	}
25397836SJohn.Forte@Sun.COM 	if (!found) {
25407836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "Deregister session called for non existent"
25417836SJohn.Forte@Sun.COM 		    " session");
25427836SJohn.Forte@Sun.COM 	}
25437836SJohn.Forte@Sun.COM 	ilport->ilport_nsessions--;
25447836SJohn.Forte@Sun.COM 	rw_exit(&ilport->ilport_lock);
25457836SJohn.Forte@Sun.COM 
25467836SJohn.Forte@Sun.COM 	(void) stmf_session_destroy_lun_map(ilport, iss);
25477836SJohn.Forte@Sun.COM }
25487836SJohn.Forte@Sun.COM 
25497836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *
25507836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked)
25517836SJohn.Forte@Sun.COM {
25527836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
25537836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
25547836SJohn.Forte@Sun.COM 
25557836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
25567836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
25578662SJordan.Vaughan@Sun.com 	    ilport = ilport->ilport_next) {
25587836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
25597836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
25608662SJordan.Vaughan@Sun.com 		    iss = iss->iss_next) {
25617836SJohn.Forte@Sun.COM 			if (iss->iss_ss->ss_session_id == session_id) {
25627836SJohn.Forte@Sun.COM 				if (!stay_locked)
25637836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
25647836SJohn.Forte@Sun.COM 				mutex_exit(&stmf_state.stmf_lock);
25657836SJohn.Forte@Sun.COM 				return (iss);
25667836SJohn.Forte@Sun.COM 			}
25677836SJohn.Forte@Sun.COM 		}
25687836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
25697836SJohn.Forte@Sun.COM 	}
25707836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
25717836SJohn.Forte@Sun.COM 	return (NULL);
25727836SJohn.Forte@Sun.COM }
25737836SJohn.Forte@Sun.COM 
25747836SJohn.Forte@Sun.COM void
25757836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
25767836SJohn.Forte@Sun.COM {
25777836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itlpp;
25787836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
25797836SJohn.Forte@Sun.COM 
25807836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED);
25817836SJohn.Forte@Sun.COM 
25827836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
25837836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
25847836SJohn.Forte@Sun.COM 	for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL;
25858662SJordan.Vaughan@Sun.com 	    itlpp = &(*itlpp)->itl_next) {
25867836SJohn.Forte@Sun.COM 		if ((*itlpp) == itl)
25877836SJohn.Forte@Sun.COM 			break;
25887836SJohn.Forte@Sun.COM 	}
25897836SJohn.Forte@Sun.COM 	ASSERT((*itlpp) != NULL);
25907836SJohn.Forte@Sun.COM 	*itlpp = itl->itl_next;
25917836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
25927836SJohn.Forte@Sun.COM 	lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle,
25938662SJordan.Vaughan@Sun.com 	    (uint32_t)itl->itl_hdlrm_reason);
25947836SJohn.Forte@Sun.COM 	kmem_free(itl, sizeof (*itl));
25957836SJohn.Forte@Sun.COM }
25967836SJohn.Forte@Sun.COM 
25977836SJohn.Forte@Sun.COM stmf_status_t
25987836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun,
25997836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
26007836SJohn.Forte@Sun.COM {
26017836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
26027836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
26037836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
26047836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
26057836SJohn.Forte@Sun.COM 	uint16_t n;
26067836SJohn.Forte@Sun.COM 
26077836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
26087836SJohn.Forte@Sun.COM 	if (ss == NULL) {
26097836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
26107836SJohn.Forte@Sun.COM 		if (iss == NULL)
26117836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
26127836SJohn.Forte@Sun.COM 	} else {
26137836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
26147836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
26157836SJohn.Forte@Sun.COM 	}
26167836SJohn.Forte@Sun.COM 
26177836SJohn.Forte@Sun.COM 	n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
26187836SJohn.Forte@Sun.COM 	lun_map_ent = (stmf_lun_map_ent_t *)
26198662SJordan.Vaughan@Sun.com 	    stmf_get_ent_from_map(iss->iss_sm, n);
26207836SJohn.Forte@Sun.COM 	if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) {
26217836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26227836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
26237836SJohn.Forte@Sun.COM 	}
26247836SJohn.Forte@Sun.COM 	if (lun_map_ent->ent_itl_datap != NULL) {
26257836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26267836SJohn.Forte@Sun.COM 		return (STMF_ALREADY);
26277836SJohn.Forte@Sun.COM 	}
26287836SJohn.Forte@Sun.COM 
26297836SJohn.Forte@Sun.COM 	itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP);
26307836SJohn.Forte@Sun.COM 	if (itl == NULL) {
26317836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
26327836SJohn.Forte@Sun.COM 		return (STMF_ALLOC_FAILURE);
26337836SJohn.Forte@Sun.COM 	}
26347836SJohn.Forte@Sun.COM 
26357836SJohn.Forte@Sun.COM 	itl->itl_counter = 1;
26367836SJohn.Forte@Sun.COM 	itl->itl_lun = n;
26377836SJohn.Forte@Sun.COM 	itl->itl_handle = itl_handle;
26387836SJohn.Forte@Sun.COM 	itl->itl_session = iss;
26397836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
26407836SJohn.Forte@Sun.COM 	itl->itl_next = ilu->ilu_itl_list;
26417836SJohn.Forte@Sun.COM 	ilu->ilu_itl_list = itl;
26427836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
26437836SJohn.Forte@Sun.COM 	lun_map_ent->ent_itl_datap = itl;
26447836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
26457836SJohn.Forte@Sun.COM 
26467836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
26477836SJohn.Forte@Sun.COM }
26487836SJohn.Forte@Sun.COM 
26497836SJohn.Forte@Sun.COM void
26507836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason)
26517836SJohn.Forte@Sun.COM {
26527836SJohn.Forte@Sun.COM 	uint8_t old, new;
26537836SJohn.Forte@Sun.COM 
26547836SJohn.Forte@Sun.COM 	do {
26557836SJohn.Forte@Sun.COM 		old = new = itl->itl_flags;
26567836SJohn.Forte@Sun.COM 		if (old & STMF_ITL_BEING_TERMINATED)
26577836SJohn.Forte@Sun.COM 			return;
26587836SJohn.Forte@Sun.COM 		new |= STMF_ITL_BEING_TERMINATED;
26597836SJohn.Forte@Sun.COM 	} while (atomic_cas_8(&itl->itl_flags, old, new) != old);
26607836SJohn.Forte@Sun.COM 	itl->itl_hdlrm_reason = hdlrm_reason;
26617836SJohn.Forte@Sun.COM 
26627836SJohn.Forte@Sun.COM 	ASSERT(itl->itl_counter);
26637836SJohn.Forte@Sun.COM 
26647836SJohn.Forte@Sun.COM 	if (atomic_add_32_nv(&itl->itl_counter, -1))
26657836SJohn.Forte@Sun.COM 		return;
26667836SJohn.Forte@Sun.COM 
26677836SJohn.Forte@Sun.COM 	drv_usecwait(10);
26687836SJohn.Forte@Sun.COM 	if (itl->itl_counter)
26697836SJohn.Forte@Sun.COM 		return;
26707836SJohn.Forte@Sun.COM 
26717836SJohn.Forte@Sun.COM 	stmf_release_itl_handle(lu, itl);
26727836SJohn.Forte@Sun.COM }
26737836SJohn.Forte@Sun.COM 
26747836SJohn.Forte@Sun.COM stmf_status_t
26757836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu)
26767836SJohn.Forte@Sun.COM {
26777836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
26787836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
26797836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
26807836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
26817836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
26827836SJohn.Forte@Sun.COM 	uint32_t nmaps, nu;
26837836SJohn.Forte@Sun.COM 	stmf_itl_data_t **itl_list;
26847836SJohn.Forte@Sun.COM 	int i;
26857836SJohn.Forte@Sun.COM 
26867836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
26877836SJohn.Forte@Sun.COM 
26887836SJohn.Forte@Sun.COM dereg_itl_start:;
26897836SJohn.Forte@Sun.COM 	nmaps = ilu->ilu_ref_cnt;
26907836SJohn.Forte@Sun.COM 	if (nmaps == 0)
26917836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
26927836SJohn.Forte@Sun.COM 	itl_list = (stmf_itl_data_t **)kmem_zalloc(
26938662SJordan.Vaughan@Sun.com 	    nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP);
26947836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
26957836SJohn.Forte@Sun.COM 	if (nmaps != ilu->ilu_ref_cnt) {
26967836SJohn.Forte@Sun.COM 		/* Something changed, start all over */
26977836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
26987836SJohn.Forte@Sun.COM 		kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
26997836SJohn.Forte@Sun.COM 		goto dereg_itl_start;
27007836SJohn.Forte@Sun.COM 	}
27017836SJohn.Forte@Sun.COM 	nu = 0;
27027836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
27038662SJordan.Vaughan@Sun.com 	    ilport = ilport->ilport_next) {
27047836SJohn.Forte@Sun.COM 		rw_enter(&ilport->ilport_lock, RW_WRITER);
27057836SJohn.Forte@Sun.COM 		for (iss = ilport->ilport_ss_list; iss != NULL;
27068662SJordan.Vaughan@Sun.com 		    iss = iss->iss_next) {
27077836SJohn.Forte@Sun.COM 			lm = iss->iss_sm;
27087836SJohn.Forte@Sun.COM 			if (!lm)
27097836SJohn.Forte@Sun.COM 				continue;
27107836SJohn.Forte@Sun.COM 			for (i = 0; i < lm->lm_nentries; i++) {
27117836SJohn.Forte@Sun.COM 				if (lm->lm_plus[i] == NULL)
27127836SJohn.Forte@Sun.COM 					continue;
27137836SJohn.Forte@Sun.COM 				ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
27147836SJohn.Forte@Sun.COM 				if ((ent->ent_lu == lu) &&
27158662SJordan.Vaughan@Sun.com 				    (ent->ent_itl_datap)) {
27167836SJohn.Forte@Sun.COM 					itl_list[nu++] = ent->ent_itl_datap;
27177836SJohn.Forte@Sun.COM 					ent->ent_itl_datap = NULL;
27187836SJohn.Forte@Sun.COM 					if (nu == nmaps) {
27197836SJohn.Forte@Sun.COM 						rw_exit(&ilport->ilport_lock);
27207836SJohn.Forte@Sun.COM 						goto dai_scan_done;
27217836SJohn.Forte@Sun.COM 					}
27227836SJohn.Forte@Sun.COM 				}
27237836SJohn.Forte@Sun.COM 			} /* lun table for a session */
27247836SJohn.Forte@Sun.COM 		} /* sessions */
27257836SJohn.Forte@Sun.COM 		rw_exit(&ilport->ilport_lock);
27267836SJohn.Forte@Sun.COM 	} /* ports */
27277836SJohn.Forte@Sun.COM 
27287836SJohn.Forte@Sun.COM dai_scan_done:
27297836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
27307836SJohn.Forte@Sun.COM 
27317836SJohn.Forte@Sun.COM 	for (i = 0; i < nu; i++) {
27327836SJohn.Forte@Sun.COM 		stmf_do_itl_dereg(lu, itl_list[i],
27338662SJordan.Vaughan@Sun.com 		    STMF_ITL_REASON_DEREG_REQUEST);
27347836SJohn.Forte@Sun.COM 	}
27357836SJohn.Forte@Sun.COM 	kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
27367836SJohn.Forte@Sun.COM 
27377836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
27387836SJohn.Forte@Sun.COM }
27397836SJohn.Forte@Sun.COM 
27407836SJohn.Forte@Sun.COM stmf_status_t
27417836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
27427836SJohn.Forte@Sun.COM     stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
27437836SJohn.Forte@Sun.COM {
27447836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
27457836SJohn.Forte@Sun.COM 	stmf_itl_data_t *itl;
27467836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
27477836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
27487836SJohn.Forte@Sun.COM 	int i;
27497836SJohn.Forte@Sun.COM 	uint16_t n;
27507836SJohn.Forte@Sun.COM 
27517836SJohn.Forte@Sun.COM 	if (ss == NULL) {
27527836SJohn.Forte@Sun.COM 		if (session_id == STMF_SESSION_ID_NONE)
27537836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
27547836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
27557836SJohn.Forte@Sun.COM 		if (iss == NULL)
27567836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
27577836SJohn.Forte@Sun.COM 	} else {
27587836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
27597836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
27607836SJohn.Forte@Sun.COM 	}
27617836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
27627836SJohn.Forte@Sun.COM 	if (lm == NULL) {
27637836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
27647836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
27657836SJohn.Forte@Sun.COM 	}
27667836SJohn.Forte@Sun.COM 
27677836SJohn.Forte@Sun.COM 	if (lun) {
27687836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
27697836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
27708662SJordan.Vaughan@Sun.com 		    stmf_get_ent_from_map(iss->iss_sm, n);
27717836SJohn.Forte@Sun.COM 	} else {
27727836SJohn.Forte@Sun.COM 		if (itl_handle == NULL) {
27737836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
27747836SJohn.Forte@Sun.COM 			return (STMF_INVALID_ARG);
27757836SJohn.Forte@Sun.COM 		}
27767836SJohn.Forte@Sun.COM 		ent = NULL;
27777836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
27787836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
27797836SJohn.Forte@Sun.COM 				continue;
27807836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
27817836SJohn.Forte@Sun.COM 			if (ent->ent_itl_datap &&
27827836SJohn.Forte@Sun.COM 			    (ent->ent_itl_datap->itl_handle == itl_handle)) {
27837836SJohn.Forte@Sun.COM 				break;
27847836SJohn.Forte@Sun.COM 			}
27857836SJohn.Forte@Sun.COM 		}
27867836SJohn.Forte@Sun.COM 	}
27877836SJohn.Forte@Sun.COM 	if ((ent == NULL) || (ent->ent_lu != lu) ||
27888662SJordan.Vaughan@Sun.com 	    (ent->ent_itl_datap == NULL)) {
27897836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
27907836SJohn.Forte@Sun.COM 		return (STMF_NOT_FOUND);
27917836SJohn.Forte@Sun.COM 	}
27927836SJohn.Forte@Sun.COM 	itl = ent->ent_itl_datap;
27937836SJohn.Forte@Sun.COM 	ent->ent_itl_datap = NULL;
27947836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
27957836SJohn.Forte@Sun.COM 	stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
27967836SJohn.Forte@Sun.COM 
27977836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
27987836SJohn.Forte@Sun.COM }
27997836SJohn.Forte@Sun.COM 
28007836SJohn.Forte@Sun.COM stmf_status_t
28017836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
28027836SJohn.Forte@Sun.COM     uint64_t session_id, void **itl_handle_retp)
28037836SJohn.Forte@Sun.COM {
28047836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
28057836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *ent;
28067836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
28077836SJohn.Forte@Sun.COM 	stmf_status_t ret;
28087836SJohn.Forte@Sun.COM 	int i;
28097836SJohn.Forte@Sun.COM 	uint16_t n;
28107836SJohn.Forte@Sun.COM 
28117836SJohn.Forte@Sun.COM 	if (ss == NULL) {
28127836SJohn.Forte@Sun.COM 		iss = stmf_session_id_to_issptr(session_id, 1);
28137836SJohn.Forte@Sun.COM 		if (iss == NULL)
28147836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
28157836SJohn.Forte@Sun.COM 	} else {
28167836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
28177836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
28187836SJohn.Forte@Sun.COM 	}
28197836SJohn.Forte@Sun.COM 
28207836SJohn.Forte@Sun.COM 	ent = NULL;
28217836SJohn.Forte@Sun.COM 	if (lun == NULL) {
28227836SJohn.Forte@Sun.COM 		lm = iss->iss_sm;
28237836SJohn.Forte@Sun.COM 		for (i = 0; i < lm->lm_nentries; i++) {
28247836SJohn.Forte@Sun.COM 			if (lm->lm_plus[i] == NULL)
28257836SJohn.Forte@Sun.COM 				continue;
28267836SJohn.Forte@Sun.COM 			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
28277836SJohn.Forte@Sun.COM 			if (ent->ent_lu == lu)
28287836SJohn.Forte@Sun.COM 				break;
28297836SJohn.Forte@Sun.COM 		}
28307836SJohn.Forte@Sun.COM 	} else {
28317836SJohn.Forte@Sun.COM 		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
28327836SJohn.Forte@Sun.COM 		ent = (stmf_lun_map_ent_t *)
28338662SJordan.Vaughan@Sun.com 		    stmf_get_ent_from_map(iss->iss_sm, n);
28347836SJohn.Forte@Sun.COM 		if (lu && (ent->ent_lu != lu))
28357836SJohn.Forte@Sun.COM 			ent = NULL;
28367836SJohn.Forte@Sun.COM 	}
28377836SJohn.Forte@Sun.COM 	if (ent && ent->ent_itl_datap) {
28387836SJohn.Forte@Sun.COM 		*itl_handle_retp = ent->ent_itl_datap->itl_handle;
28397836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
28407836SJohn.Forte@Sun.COM 	} else {
28417836SJohn.Forte@Sun.COM 		ret = STMF_NOT_FOUND;
28427836SJohn.Forte@Sun.COM 	}
28437836SJohn.Forte@Sun.COM 
28447836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
28457836SJohn.Forte@Sun.COM 	return (ret);
28467836SJohn.Forte@Sun.COM }
28477836SJohn.Forte@Sun.COM 
28487836SJohn.Forte@Sun.COM stmf_data_buf_t *
28497836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
28507836SJohn.Forte@Sun.COM     uint32_t flags)
28517836SJohn.Forte@Sun.COM {
28527836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
28537836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
28547836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
28557836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
28567836SJohn.Forte@Sun.COM 	uint8_t ndx;
28577836SJohn.Forte@Sun.COM 
28587836SJohn.Forte@Sun.COM 	ndx = stmf_first_zero[itask->itask_allocated_buf_map];
28597836SJohn.Forte@Sun.COM 	if (ndx == 0xff)
28607836SJohn.Forte@Sun.COM 		return (NULL);
28617836SJohn.Forte@Sun.COM 	dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf(
28627836SJohn.Forte@Sun.COM 	    task, size, pminsize, flags);
28637836SJohn.Forte@Sun.COM 	if (dbuf) {
28647836SJohn.Forte@Sun.COM 		task->task_cur_nbufs++;
28657836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map |= (1 << ndx);
28667836SJohn.Forte@Sun.COM 		dbuf->db_handle = ndx;
28677836SJohn.Forte@Sun.COM 		return (dbuf);
28687836SJohn.Forte@Sun.COM 	}
28697836SJohn.Forte@Sun.COM 
28707836SJohn.Forte@Sun.COM 	return (NULL);
28717836SJohn.Forte@Sun.COM }
28727836SJohn.Forte@Sun.COM 
28737836SJohn.Forte@Sun.COM void
28747836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf)
28757836SJohn.Forte@Sun.COM {
28767836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
28777836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
28787836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
28797836SJohn.Forte@Sun.COM 
28807836SJohn.Forte@Sun.COM 	itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle);
28817836SJohn.Forte@Sun.COM 	task->task_cur_nbufs--;
28827836SJohn.Forte@Sun.COM 	lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf);
28837836SJohn.Forte@Sun.COM }
28847836SJohn.Forte@Sun.COM 
28857836SJohn.Forte@Sun.COM stmf_data_buf_t *
28867836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h)
28877836SJohn.Forte@Sun.COM {
28887836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
28897836SJohn.Forte@Sun.COM 
28907836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
28917836SJohn.Forte@Sun.COM 	if (h > 3)
28927836SJohn.Forte@Sun.COM 		return (NULL);
28937836SJohn.Forte@Sun.COM 	return (itask->itask_dbufs[h]);
28947836SJohn.Forte@Sun.COM }
28957836SJohn.Forte@Sun.COM 
28967836SJohn.Forte@Sun.COM /* ARGSUSED */
28977836SJohn.Forte@Sun.COM struct scsi_task *
28987836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss,
28997836SJohn.Forte@Sun.COM 			uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id)
29007836SJohn.Forte@Sun.COM {
29017836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
29027836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
29037836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
29047836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
29057836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t **ppitask;
29067836SJohn.Forte@Sun.COM 	scsi_task_t *task;
29077836SJohn.Forte@Sun.COM 	uint64_t *p;
29087836SJohn.Forte@Sun.COM 	uint8_t	*l;
29097836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lun_map_ent;
29107836SJohn.Forte@Sun.COM 	uint16_t cdb_length;
29117836SJohn.Forte@Sun.COM 	uint16_t luNbr;
29127836SJohn.Forte@Sun.COM 	uint8_t new_task = 0;
29137836SJohn.Forte@Sun.COM 
29147836SJohn.Forte@Sun.COM 	/*
29157836SJohn.Forte@Sun.COM 	 * We allocate 7 extra bytes for CDB to provide a cdb pointer which
29167836SJohn.Forte@Sun.COM 	 * is guaranteed to be 8 byte aligned. Some LU providers like OSD
29177836SJohn.Forte@Sun.COM 	 * depend upon this alignment.
29187836SJohn.Forte@Sun.COM 	 */
29197836SJohn.Forte@Sun.COM 	if (cdb_length_in >= 16)
29207836SJohn.Forte@Sun.COM 		cdb_length = cdb_length_in + 7;
29217836SJohn.Forte@Sun.COM 	else
29227836SJohn.Forte@Sun.COM 		cdb_length = 16 + 7;
29237836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
29247836SJohn.Forte@Sun.COM 	luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
29257836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
29267836SJohn.Forte@Sun.COM 	lun_map_ent =
29277836SJohn.Forte@Sun.COM 	    (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr);
29287836SJohn.Forte@Sun.COM 	if (!lun_map_ent) {
29297836SJohn.Forte@Sun.COM 		lu = dlun0;
29307836SJohn.Forte@Sun.COM 	} else {
29317836SJohn.Forte@Sun.COM 		lu = lun_map_ent->ent_lu;
29327836SJohn.Forte@Sun.COM 	}
29337836SJohn.Forte@Sun.COM 	ilu = lu->lu_stmf_private;
29347836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
29357836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
29367836SJohn.Forte@Sun.COM 		return (NULL);
29377836SJohn.Forte@Sun.COM 	}
29387836SJohn.Forte@Sun.COM 	do {
29397836SJohn.Forte@Sun.COM 		if (ilu->ilu_free_tasks == NULL) {
29407836SJohn.Forte@Sun.COM 			new_task = 1;
29417836SJohn.Forte@Sun.COM 			break;
29427836SJohn.Forte@Sun.COM 		}
29437836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
29447836SJohn.Forte@Sun.COM 		for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) &&
29457836SJohn.Forte@Sun.COM 		    ((*ppitask)->itask_cdb_buf_size < cdb_length);
29468662SJordan.Vaughan@Sun.com 		    ppitask = &((*ppitask)->itask_lu_free_next))
29478662SJordan.Vaughan@Sun.com 			;
29487836SJohn.Forte@Sun.COM 		if (*ppitask) {
29497836SJohn.Forte@Sun.COM 			itask = *ppitask;
29507836SJohn.Forte@Sun.COM 			*ppitask = (*ppitask)->itask_lu_free_next;
29517836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_free--;
29527836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free)
29537836SJohn.Forte@Sun.COM 				ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
29547836SJohn.Forte@Sun.COM 		} else {
29557836SJohn.Forte@Sun.COM 			new_task = 1;
29567836SJohn.Forte@Sun.COM 		}
29577836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
29587836SJohn.Forte@Sun.COM 	/* CONSTCOND */
29597836SJohn.Forte@Sun.COM 	} while (0);
29607836SJohn.Forte@Sun.COM 
29617836SJohn.Forte@Sun.COM 	if (!new_task) {
29627836SJohn.Forte@Sun.COM 		task = itask->itask_task;
29637836SJohn.Forte@Sun.COM 		task->task_timeout = 0;
29647836SJohn.Forte@Sun.COM 		p = (uint64_t *)&task->task_flags;
29657836SJohn.Forte@Sun.COM 		*p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0;
29667836SJohn.Forte@Sun.COM 		itask->itask_ncmds = 0;
29677836SJohn.Forte@Sun.COM 	} else {
29687836SJohn.Forte@Sun.COM 		task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK,
29697836SJohn.Forte@Sun.COM 		    cdb_length, AF_FORCE_NOSLEEP);
29707836SJohn.Forte@Sun.COM 		if (task == NULL) {
29717836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
29727836SJohn.Forte@Sun.COM 			return (NULL);
29737836SJohn.Forte@Sun.COM 		}
29747836SJohn.Forte@Sun.COM 		task->task_lu = lu;
29757836SJohn.Forte@Sun.COM 		l = task->task_lun_no;
29767836SJohn.Forte@Sun.COM 		l[0] = lun[0];
29777836SJohn.Forte@Sun.COM 		l[1] = lun[1];
29787836SJohn.Forte@Sun.COM 		l[2] = lun[2];
29797836SJohn.Forte@Sun.COM 		l[3] = lun[3];
29807836SJohn.Forte@Sun.COM 		l[4] = lun[4];
29817836SJohn.Forte@Sun.COM 		l[5] = lun[5];
29827836SJohn.Forte@Sun.COM 		l[6] = lun[6];
29837836SJohn.Forte@Sun.COM 		l[7] = lun[7];
29847836SJohn.Forte@Sun.COM 		task->task_cdb = (uint8_t *)task->task_port_private;
29857836SJohn.Forte@Sun.COM 		if ((ulong_t)(task->task_cdb) & 7ul) {
29867836SJohn.Forte@Sun.COM 			task->task_cdb = (uint8_t *)(((ulong_t)
29877836SJohn.Forte@Sun.COM 			    (task->task_cdb) + 7ul) & ~(7ul));
29887836SJohn.Forte@Sun.COM 		}
29897836SJohn.Forte@Sun.COM 		itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
29907836SJohn.Forte@Sun.COM 		itask->itask_cdb_buf_size = cdb_length;
29917836SJohn.Forte@Sun.COM 	}
29927836SJohn.Forte@Sun.COM 	task->task_session = ss;
29937836SJohn.Forte@Sun.COM 	task->task_lport = lport;
29947836SJohn.Forte@Sun.COM 	task->task_cdb_length = cdb_length_in;
29957836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_TRANSITION;
29967836SJohn.Forte@Sun.COM 
29977836SJohn.Forte@Sun.COM 	if (new_task) {
29987836SJohn.Forte@Sun.COM 		if (lu->lu_task_alloc(task) != STMF_SUCCESS) {
29997836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
30007836SJohn.Forte@Sun.COM 			stmf_free(task);
30017836SJohn.Forte@Sun.COM 			return (NULL);
30027836SJohn.Forte@Sun.COM 		}
30037836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
30047836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
30057836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
30067836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
30077836SJohn.Forte@Sun.COM 			stmf_free(task);
30087836SJohn.Forte@Sun.COM 			return (NULL);
30097836SJohn.Forte@Sun.COM 		}
30107836SJohn.Forte@Sun.COM 		itask->itask_lu_next = ilu->ilu_tasks;
30117836SJohn.Forte@Sun.COM 		if (ilu->ilu_tasks)
30127836SJohn.Forte@Sun.COM 			ilu->ilu_tasks->itask_lu_prev = itask;
30137836SJohn.Forte@Sun.COM 		ilu->ilu_tasks = itask;
30147836SJohn.Forte@Sun.COM 		/* kmem_zalloc automatically makes itask->itask_lu_prev NULL */
30157836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks++;
30167836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30177836SJohn.Forte@Sun.COM 	}
30187836SJohn.Forte@Sun.COM 
30197836SJohn.Forte@Sun.COM 	itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr;
30207836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, 1);
30217836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
30227836SJohn.Forte@Sun.COM 
30237836SJohn.Forte@Sun.COM 	if ((lun_map_ent != NULL) && ((itask->itask_itl_datap =
30247836SJohn.Forte@Sun.COM 	    lun_map_ent->ent_itl_datap) != NULL)) {
30257836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_itl_datap->itl_counter, 1);
30267836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle;
30277836SJohn.Forte@Sun.COM 	} else {
30287836SJohn.Forte@Sun.COM 		itask->itask_itl_datap = NULL;
30297836SJohn.Forte@Sun.COM 		task->task_lu_itl_handle = NULL;
30307836SJohn.Forte@Sun.COM 	}
30317836SJohn.Forte@Sun.COM 
30327836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
30337836SJohn.Forte@Sun.COM 	return (task);
30347836SJohn.Forte@Sun.COM }
30357836SJohn.Forte@Sun.COM 
30367836SJohn.Forte@Sun.COM void
30377836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task)
30387836SJohn.Forte@Sun.COM {
30397836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
30407836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
30417836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
30427836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
30437836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
30447836SJohn.Forte@Sun.COM 
30457836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
30467836SJohn.Forte@Sun.COM 	itask->itask_flags = ITASK_IN_FREE_LIST;
30477836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
30487836SJohn.Forte@Sun.COM 	itask->itask_lu_free_next = ilu->ilu_free_tasks;
30497836SJohn.Forte@Sun.COM 	ilu->ilu_free_tasks = itask;
30507836SJohn.Forte@Sun.COM 	ilu->ilu_ntasks_free++;
30517836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
30527836SJohn.Forte@Sun.COM 	atomic_add_32(itask->itask_ilu_task_cntr, -1);
30537836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
30547836SJohn.Forte@Sun.COM }
30557836SJohn.Forte@Sun.COM 
30567836SJohn.Forte@Sun.COM void
30577836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu)
30587836SJohn.Forte@Sun.COM {
30597836SJohn.Forte@Sun.COM 	uint32_t	num_to_release, ndx;
30607836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
30617836SJohn.Forte@Sun.COM 	stmf_lu_t	*lu = ilu->ilu_lu;
30627836SJohn.Forte@Sun.COM 
30637836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free);
30647836SJohn.Forte@Sun.COM 
30657836SJohn.Forte@Sun.COM 	/* free half of the minimal free of the free tasks */
30667836SJohn.Forte@Sun.COM 	num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2;
30677836SJohn.Forte@Sun.COM 	if (!num_to_release) {
30687836SJohn.Forte@Sun.COM 		return;
30697836SJohn.Forte@Sun.COM 	}
30707836SJohn.Forte@Sun.COM 	for (ndx = 0; ndx < num_to_release; ndx++) {
30717836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
30727836SJohn.Forte@Sun.COM 		itask = ilu->ilu_free_tasks;
30737836SJohn.Forte@Sun.COM 		if (itask == NULL) {
30747836SJohn.Forte@Sun.COM 			mutex_exit(&ilu->ilu_task_lock);
30757836SJohn.Forte@Sun.COM 			break;
30767836SJohn.Forte@Sun.COM 		}
30777836SJohn.Forte@Sun.COM 		ilu->ilu_free_tasks = itask->itask_lu_free_next;
30787836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_free--;
30797836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30807836SJohn.Forte@Sun.COM 
30817836SJohn.Forte@Sun.COM 		lu->lu_task_free(itask->itask_task);
30827836SJohn.Forte@Sun.COM 		mutex_enter(&ilu->ilu_task_lock);
30837836SJohn.Forte@Sun.COM 		if (itask->itask_lu_next)
30847836SJohn.Forte@Sun.COM 			itask->itask_lu_next->itask_lu_prev =
30857836SJohn.Forte@Sun.COM 			    itask->itask_lu_prev;
30867836SJohn.Forte@Sun.COM 		if (itask->itask_lu_prev)
30877836SJohn.Forte@Sun.COM 			itask->itask_lu_prev->itask_lu_next =
30887836SJohn.Forte@Sun.COM 			    itask->itask_lu_next;
30897836SJohn.Forte@Sun.COM 		else
30907836SJohn.Forte@Sun.COM 			ilu->ilu_tasks = itask->itask_lu_next;
30917836SJohn.Forte@Sun.COM 
30927836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks--;
30937836SJohn.Forte@Sun.COM 		mutex_exit(&ilu->ilu_task_lock);
30947836SJohn.Forte@Sun.COM 		stmf_free(itask->itask_task);
30957836SJohn.Forte@Sun.COM 	}
30967836SJohn.Forte@Sun.COM }
30977836SJohn.Forte@Sun.COM 
30987836SJohn.Forte@Sun.COM /*
30997836SJohn.Forte@Sun.COM  * Called with stmf_lock held
31007836SJohn.Forte@Sun.COM  */
31017836SJohn.Forte@Sun.COM void
31027836SJohn.Forte@Sun.COM stmf_check_freetask()
31037836SJohn.Forte@Sun.COM {
31047836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
31057836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
31067836SJohn.Forte@Sun.COM 
31077836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_draining may get changed after stmf_lock is released */
31087836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) {
31097836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
31107836SJohn.Forte@Sun.COM 		if (!ilu->ilu_ntasks_min_free) {
31117836SJohn.Forte@Sun.COM 			ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
31127836SJohn.Forte@Sun.COM 			continue;
31137836SJohn.Forte@Sun.COM 		}
31147836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
31157836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
31167836SJohn.Forte@Sun.COM 		stmf_task_lu_check_freelist(ilu);
31177836SJohn.Forte@Sun.COM 		/*
31187836SJohn.Forte@Sun.COM 		 * we do not care about the accuracy of
31197836SJohn.Forte@Sun.COM 		 * ilu_ntasks_min_free, so we don't lock here
31207836SJohn.Forte@Sun.COM 		 */
31217836SJohn.Forte@Sun.COM 		ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
31227836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
31237836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
31247836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
31257836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
31267836SJohn.Forte@Sun.COM 			break;
31277836SJohn.Forte@Sun.COM 	}
31287836SJohn.Forte@Sun.COM }
31297836SJohn.Forte@Sun.COM 
31307836SJohn.Forte@Sun.COM void
31317836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu)
31327836SJohn.Forte@Sun.COM {
31337836SJohn.Forte@Sun.COM 	clock_t l = ddi_get_lbolt();
31347836SJohn.Forte@Sun.COM 	clock_t ps = drv_usectohz(1000000);
31357836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
31367836SJohn.Forte@Sun.COM 	scsi_task_t *task;
31377836SJohn.Forte@Sun.COM 	uint32_t to;
31387836SJohn.Forte@Sun.COM 
31397836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
31407836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
31417836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
31427836SJohn.Forte@Sun.COM 		if (itask->itask_flags & (ITASK_IN_FREE_LIST |
31437836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) {
31447836SJohn.Forte@Sun.COM 			continue;
31457836SJohn.Forte@Sun.COM 		}
31467836SJohn.Forte@Sun.COM 		task = itask->itask_task;
31477836SJohn.Forte@Sun.COM 		if (task->task_timeout == 0)
31487836SJohn.Forte@Sun.COM 			to = stmf_default_task_timeout;
31497836SJohn.Forte@Sun.COM 		else
31507836SJohn.Forte@Sun.COM 			to = task->task_timeout;
31517836SJohn.Forte@Sun.COM 		if ((itask->itask_start_time + (to * ps)) > l)
31527836SJohn.Forte@Sun.COM 			continue;
31537836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
31547836SJohn.Forte@Sun.COM 		    STMF_TIMEOUT, NULL);
31557836SJohn.Forte@Sun.COM 	}
31567836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
31577836SJohn.Forte@Sun.COM }
31587836SJohn.Forte@Sun.COM 
31597836SJohn.Forte@Sun.COM /*
31607836SJohn.Forte@Sun.COM  * Called with stmf_lock held
31617836SJohn.Forte@Sun.COM  */
31627836SJohn.Forte@Sun.COM void
31637836SJohn.Forte@Sun.COM stmf_check_ilu_timing()
31647836SJohn.Forte@Sun.COM {
31657836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
31667836SJohn.Forte@Sun.COM 	clock_t	endtime = ddi_get_lbolt() + drv_usectohz(10000);
31677836SJohn.Forte@Sun.COM 
31687836SJohn.Forte@Sun.COM 	/* stmf_svc_ilu_timing may get changed after stmf_lock is released */
31697836SJohn.Forte@Sun.COM 	while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) {
31707836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
31717836SJohn.Forte@Sun.COM 		if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) {
31727836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr2 == 0) {
31737836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2;
31747836SJohn.Forte@Sun.COM 				continue;
31757836SJohn.Forte@Sun.COM 			}
31767836SJohn.Forte@Sun.COM 		} else {
31777836SJohn.Forte@Sun.COM 			if (ilu->ilu_task_cntr1 == 0) {
31787836SJohn.Forte@Sun.COM 				ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
31797836SJohn.Forte@Sun.COM 				continue;
31807836SJohn.Forte@Sun.COM 			}
31817836SJohn.Forte@Sun.COM 		}
31827836SJohn.Forte@Sun.COM 		/*
31837836SJohn.Forte@Sun.COM 		 * If we are here then it means that there is some slowdown
31847836SJohn.Forte@Sun.COM 		 * in tasks on this lu. We need to check.
31857836SJohn.Forte@Sun.COM 		 */
31867836SJohn.Forte@Sun.COM 		ilu->ilu_flags |= ILU_STALL_DEREGISTER;
31877836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
31887836SJohn.Forte@Sun.COM 		stmf_do_ilu_timeouts(ilu);
31897836SJohn.Forte@Sun.COM 		mutex_enter(&stmf_state.stmf_lock);
31907836SJohn.Forte@Sun.COM 		ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
31917836SJohn.Forte@Sun.COM 		cv_broadcast(&stmf_state.stmf_cv);
31927836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() >= endtime)
31937836SJohn.Forte@Sun.COM 			break;
31947836SJohn.Forte@Sun.COM 	}
31957836SJohn.Forte@Sun.COM }
31967836SJohn.Forte@Sun.COM 
31977836SJohn.Forte@Sun.COM /*
31987836SJohn.Forte@Sun.COM  * Kills all tasks on a lu except tm_task
31997836SJohn.Forte@Sun.COM  */
32007836SJohn.Forte@Sun.COM void
32017836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s)
32027836SJohn.Forte@Sun.COM {
32037836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
32047836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
32057836SJohn.Forte@Sun.COM 
32067836SJohn.Forte@Sun.COM 	mutex_enter(&ilu->ilu_task_lock);
32077836SJohn.Forte@Sun.COM 
32087836SJohn.Forte@Sun.COM 	for (itask = ilu->ilu_tasks; itask != NULL;
32097836SJohn.Forte@Sun.COM 	    itask = itask->itask_lu_next) {
32107836SJohn.Forte@Sun.COM 		if (itask->itask_flags & ITASK_IN_FREE_LIST)
32117836SJohn.Forte@Sun.COM 			continue;
32127836SJohn.Forte@Sun.COM 		if (itask->itask_task == tm_task)
32137836SJohn.Forte@Sun.COM 			continue;
32147836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL);
32157836SJohn.Forte@Sun.COM 	}
32167836SJohn.Forte@Sun.COM 	mutex_exit(&ilu->ilu_task_lock);
32177836SJohn.Forte@Sun.COM }
32187836SJohn.Forte@Sun.COM 
32197836SJohn.Forte@Sun.COM void
32207836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport)
32217836SJohn.Forte@Sun.COM {
32227836SJohn.Forte@Sun.COM 	int i;
32237836SJohn.Forte@Sun.COM 	uint8_t map;
32247836SJohn.Forte@Sun.COM 
32257836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
32267836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
32277836SJohn.Forte@Sun.COM 			if (map & 1) {
32287836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
32297836SJohn.Forte@Sun.COM 
32307836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
32317836SJohn.Forte@Sun.COM 				if (dbuf->db_lu_private) {
32327836SJohn.Forte@Sun.COM 					dbuf->db_lu_private = NULL;
32337836SJohn.Forte@Sun.COM 				}
32347836SJohn.Forte@Sun.COM 				lport->lport_ds->ds_free_data_buf(
32357836SJohn.Forte@Sun.COM 				    lport->lport_ds, dbuf);
32367836SJohn.Forte@Sun.COM 			}
32377836SJohn.Forte@Sun.COM 			map >>= 1;
32387836SJohn.Forte@Sun.COM 		}
32397836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
32407836SJohn.Forte@Sun.COM 	}
32417836SJohn.Forte@Sun.COM }
32427836SJohn.Forte@Sun.COM 
32437836SJohn.Forte@Sun.COM void
32447836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task)
32457836SJohn.Forte@Sun.COM {
32467836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport = task->task_lport;
32477836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
32488662SJordan.Vaughan@Sun.com 	    task->task_stmf_private;
32497836SJohn.Forte@Sun.COM 
32508859STim.Szeto@Sun.COM 	DTRACE_PROBE1(stmf__task__end, scsi_task_t *, task);
32517836SJohn.Forte@Sun.COM 	stmf_free_task_bufs(itask, lport);
32527836SJohn.Forte@Sun.COM 	if (itask->itask_itl_datap) {
32537836SJohn.Forte@Sun.COM 		if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter,
32547836SJohn.Forte@Sun.COM 		    -1) == 0) {
32557836SJohn.Forte@Sun.COM 			stmf_release_itl_handle(task->task_lu,
32568662SJordan.Vaughan@Sun.com 			    itask->itask_itl_datap);
32577836SJohn.Forte@Sun.COM 		}
32587836SJohn.Forte@Sun.COM 	}
32597836SJohn.Forte@Sun.COM 	lport->lport_task_free(task);
32607836SJohn.Forte@Sun.COM 	if (itask->itask_worker) {
32617836SJohn.Forte@Sun.COM 		atomic_add_32(&stmf_cur_ntasks, -1);
32627836SJohn.Forte@Sun.COM 		atomic_add_32(&itask->itask_worker->worker_ref_count, -1);
32637836SJohn.Forte@Sun.COM 	}
32647836SJohn.Forte@Sun.COM 	/*
32657836SJohn.Forte@Sun.COM 	 * After calling stmf_task_lu_free, the task pointer can no longer
32667836SJohn.Forte@Sun.COM 	 * be trusted.
32677836SJohn.Forte@Sun.COM 	 */
32687836SJohn.Forte@Sun.COM 	stmf_task_lu_free(task);
32697836SJohn.Forte@Sun.COM }
32707836SJohn.Forte@Sun.COM 
32717836SJohn.Forte@Sun.COM void
32727836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
32737836SJohn.Forte@Sun.COM {
32747836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
32757836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
32767836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
32777836SJohn.Forte@Sun.COM 	int nv;
32787836SJohn.Forte@Sun.COM 	uint32_t old, new;
32797836SJohn.Forte@Sun.COM 	uint32_t ct;
32807836SJohn.Forte@Sun.COM 	stmf_worker_t *w, *w1;
32817836SJohn.Forte@Sun.COM 	uint8_t tm;
32827836SJohn.Forte@Sun.COM 
32837836SJohn.Forte@Sun.COM 	if (task->task_max_nbufs > 4)
32847836SJohn.Forte@Sun.COM 		task->task_max_nbufs = 4;
32857836SJohn.Forte@Sun.COM 	task->task_cur_nbufs = 0;
32867836SJohn.Forte@Sun.COM 	/* Latest value of currently running tasks */
32877836SJohn.Forte@Sun.COM 	ct = atomic_add_32_nv(&stmf_cur_ntasks, 1);
32887836SJohn.Forte@Sun.COM 
32897836SJohn.Forte@Sun.COM 	/* Select the next worker using round robin */
32907836SJohn.Forte@Sun.COM 	nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1);
32917836SJohn.Forte@Sun.COM 	if (nv >= stmf_nworkers_accepting_cmds) {
32927836SJohn.Forte@Sun.COM 		int s = nv;
32937836SJohn.Forte@Sun.COM 		do {
32947836SJohn.Forte@Sun.COM 			nv -= stmf_nworkers_accepting_cmds;
32957836SJohn.Forte@Sun.COM 		} while (nv >= stmf_nworkers_accepting_cmds);
32967836SJohn.Forte@Sun.COM 		if (nv < 0)
32977836SJohn.Forte@Sun.COM 			nv = 0;
32987836SJohn.Forte@Sun.COM 		/* Its ok if this cas fails */
32997836SJohn.Forte@Sun.COM 		(void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter,
33007836SJohn.Forte@Sun.COM 		    s, nv);
33017836SJohn.Forte@Sun.COM 	}
33027836SJohn.Forte@Sun.COM 	w = &stmf_workers[nv];
33037836SJohn.Forte@Sun.COM 
33047836SJohn.Forte@Sun.COM 	/*
33057836SJohn.Forte@Sun.COM 	 * A worker can be pinned by interrupt. So select the next one
33067836SJohn.Forte@Sun.COM 	 * if it has lower load.
33077836SJohn.Forte@Sun.COM 	 */
33087836SJohn.Forte@Sun.COM 	if ((nv + 1) >= stmf_nworkers_accepting_cmds) {
33097836SJohn.Forte@Sun.COM 		w1 = stmf_workers;
33107836SJohn.Forte@Sun.COM 	} else {
33117836SJohn.Forte@Sun.COM 		w1 = &stmf_workers[nv + 1];
33127836SJohn.Forte@Sun.COM 	}
33137836SJohn.Forte@Sun.COM 	if (w1->worker_queue_depth < w->worker_queue_depth)
33147836SJohn.Forte@Sun.COM 		w = w1;
33159435STim.Szeto@Sun.COM 
33167836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
33177836SJohn.Forte@Sun.COM 	if (((w->worker_flags & STMF_WORKER_STARTED) == 0) ||
33187836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
33197836SJohn.Forte@Sun.COM 		/*
33207836SJohn.Forte@Sun.COM 		 * Maybe we are in the middle of a change. Just go to
33217836SJohn.Forte@Sun.COM 		 * the 1st worker.
33227836SJohn.Forte@Sun.COM 		 */
33237836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
33247836SJohn.Forte@Sun.COM 		w = stmf_workers;
33257836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
33267836SJohn.Forte@Sun.COM 	}
33277836SJohn.Forte@Sun.COM 	itask->itask_worker = w;
33287836SJohn.Forte@Sun.COM 	/*
33297836SJohn.Forte@Sun.COM 	 * Track max system load inside the worker as we already have the
33307836SJohn.Forte@Sun.COM 	 * worker lock (no point implementing another lock). The service
33317836SJohn.Forte@Sun.COM 	 * thread will do the comparisons and figure out the max overall
33327836SJohn.Forte@Sun.COM 	 * system load.
33337836SJohn.Forte@Sun.COM 	 */
33347836SJohn.Forte@Sun.COM 	if (w->worker_max_sys_qdepth_pu < ct)
33357836SJohn.Forte@Sun.COM 		w->worker_max_sys_qdepth_pu = ct;
33367836SJohn.Forte@Sun.COM 
33377836SJohn.Forte@Sun.COM 	do {
33387836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
33397836SJohn.Forte@Sun.COM 		new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE;
33407836SJohn.Forte@Sun.COM 		if (task->task_mgmt_function) {
33417836SJohn.Forte@Sun.COM 			tm = task->task_mgmt_function;
33427836SJohn.Forte@Sun.COM 			if ((tm == TM_TARGET_RESET) ||
33437836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_COLD_RESET) ||
33447836SJohn.Forte@Sun.COM 			    (tm == TM_TARGET_WARM_RESET)) {
33457836SJohn.Forte@Sun.COM 				new |= ITASK_DEFAULT_HANDLING;
33467836SJohn.Forte@Sun.COM 			}
33477836SJohn.Forte@Sun.COM 		} else if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
33487836SJohn.Forte@Sun.COM 			new |= ITASK_DEFAULT_HANDLING;
33497836SJohn.Forte@Sun.COM 		}
33507836SJohn.Forte@Sun.COM 		new &= ~ITASK_IN_TRANSITION;
33517836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
33527836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
33537836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
33547836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
33557836SJohn.Forte@Sun.COM 	} else {
33567836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
33577836SJohn.Forte@Sun.COM 	}
33587836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
33597836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
33607836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
33617836SJohn.Forte@Sun.COM 	}
33627836SJohn.Forte@Sun.COM 	atomic_add_32(&w->worker_ref_count, 1);
33637836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK;
33647836SJohn.Forte@Sun.COM 	itask->itask_ncmds = 1;
33657836SJohn.Forte@Sun.COM 	if (dbuf) {
33667836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 1;
33677836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = dbuf;
33687836SJohn.Forte@Sun.COM 		dbuf->db_handle = 0;
33697836SJohn.Forte@Sun.COM 	} else {
33707836SJohn.Forte@Sun.COM 		itask->itask_allocated_buf_map = 0;
33717836SJohn.Forte@Sun.COM 		itask->itask_dbufs[0] = NULL;
33727836SJohn.Forte@Sun.COM 	}
33739435STim.Szeto@Sun.COM 
33749435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_q(task, kstat_waitq_enter);
33759435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_q(task, kstat_waitq_enter);
33769435STim.Szeto@Sun.COM 
33777836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
33787836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
33797836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
33807836SJohn.Forte@Sun.COM 
33817836SJohn.Forte@Sun.COM 	/*
33827836SJohn.Forte@Sun.COM 	 * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE
33837836SJohn.Forte@Sun.COM 	 * was set between checking of ILU_RESET_ACTIVE and clearing of the
33847836SJohn.Forte@Sun.COM 	 * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here.
33857836SJohn.Forte@Sun.COM 	 */
33867836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
33877836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL);
33887836SJohn.Forte@Sun.COM 	}
33897836SJohn.Forte@Sun.COM }
33907836SJohn.Forte@Sun.COM 
33917836SJohn.Forte@Sun.COM /*
33927836SJohn.Forte@Sun.COM  * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++
33937836SJohn.Forte@Sun.COM  * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already
33947836SJohn.Forte@Sun.COM  * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot
33957836SJohn.Forte@Sun.COM  * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course
33967836SJohn.Forte@Sun.COM  * the LU will make this call only if we call the LU's abort entry point.
33977836SJohn.Forte@Sun.COM  * we will only call that entry point if ITASK_KNOWN_TO_LU was set.
33987836SJohn.Forte@Sun.COM  *
33997836SJohn.Forte@Sun.COM  * Same logic applies for the port.
34007836SJohn.Forte@Sun.COM  *
34017836SJohn.Forte@Sun.COM  * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU
34027836SJohn.Forte@Sun.COM  * and KNOWN_TO_TGT_PORT are reset.
34037836SJohn.Forte@Sun.COM  *
34047836SJohn.Forte@Sun.COM  * +++++++++++++++++++++++++++++++++++++++++++++++
34057836SJohn.Forte@Sun.COM  */
34067836SJohn.Forte@Sun.COM 
34077836SJohn.Forte@Sun.COM stmf_status_t
34087836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
34097836SJohn.Forte@Sun.COM {
34108859STim.Szeto@Sun.COM 	stmf_status_t ret;
34118859STim.Szeto@Sun.COM 
34127836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
34137836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
34147836SJohn.Forte@Sun.COM 
34157836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
34167836SJohn.Forte@Sun.COM 		uint32_t new, old;
34177836SJohn.Forte@Sun.COM 		do {
34187836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
34197836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
34207836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
34217836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
34227836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34237836SJohn.Forte@Sun.COM 	}
34247836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
34257836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
34267836SJohn.Forte@Sun.COM #ifdef	DEBUG
34277836SJohn.Forte@Sun.COM 	if (stmf_drop_buf_counter > 0) {
34288662SJordan.Vaughan@Sun.com 		if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) ==
34298662SJordan.Vaughan@Sun.com 		    1)
34307836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
34317836SJohn.Forte@Sun.COM 	}
34327836SJohn.Forte@Sun.COM #endif
34339435STim.Szeto@Sun.COM 
34349435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_io(task, dbuf);
34359435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_io(task, dbuf);
34369435STim.Szeto@Sun.COM 
34378859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, task,
34388859STim.Szeto@Sun.COM 	    stmf_data_buf_t *, dbuf);
34398859STim.Szeto@Sun.COM 	ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags);
34408859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__xfer__end, scsi_task_t *, task,
34418859STim.Szeto@Sun.COM 	    stmf_data_buf_t *, dbuf);
34428859STim.Szeto@Sun.COM 	return (ret);
34437836SJohn.Forte@Sun.COM }
34447836SJohn.Forte@Sun.COM 
34457836SJohn.Forte@Sun.COM void
34467836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof)
34477836SJohn.Forte@Sun.COM {
34487836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
34497836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
34507836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
34517836SJohn.Forte@Sun.COM 	uint32_t new, old;
34527836SJohn.Forte@Sun.COM 	uint8_t update_queue_flags, free_it, queue_it;
34537836SJohn.Forte@Sun.COM 
34547836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
34557836SJohn.Forte@Sun.COM 	do {
34567836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
34577836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
34587836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
34597836SJohn.Forte@Sun.COM 			return;
34607836SJohn.Forte@Sun.COM 		}
34617836SJohn.Forte@Sun.COM 		free_it = 0;
34627836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
34637836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
34647836SJohn.Forte@Sun.COM 			task->task_completion_status = dbuf->db_xfer_status;
34657836SJohn.Forte@Sun.COM 			free_it = 1;
34667836SJohn.Forte@Sun.COM 		}
34677836SJohn.Forte@Sun.COM 		/*
34687836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
34697836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
34707836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
34717836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
34727836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
34737836SJohn.Forte@Sun.COM 		 * free this task.
34747836SJohn.Forte@Sun.COM 		 */
34757836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
34767836SJohn.Forte@Sun.COM 			free_it = 0;
34777836SJohn.Forte@Sun.COM 			update_queue_flags = 1;
34787836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
34797836SJohn.Forte@Sun.COM 				queue_it = 0;
34807836SJohn.Forte@Sun.COM 			} else {
34817836SJohn.Forte@Sun.COM 				queue_it = 1;
34827836SJohn.Forte@Sun.COM 				new |= ITASK_IN_WORKER_QUEUE;
34837836SJohn.Forte@Sun.COM 			}
34847836SJohn.Forte@Sun.COM 		} else {
34857836SJohn.Forte@Sun.COM 			update_queue_flags = 0;
34867836SJohn.Forte@Sun.COM 			queue_it = 0;
34877836SJohn.Forte@Sun.COM 		}
34887836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
34897836SJohn.Forte@Sun.COM 
34907836SJohn.Forte@Sun.COM 	if (update_queue_flags) {
34917836SJohn.Forte@Sun.COM 		uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE;
34927836SJohn.Forte@Sun.COM 
34937836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
34947836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] = cmd;
34957836SJohn.Forte@Sun.COM 		if (queue_it) {
34967836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
34977836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
34987836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
34997836SJohn.Forte@Sun.COM 			} else {
35007836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
35017836SJohn.Forte@Sun.COM 			}
35027836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
35037836SJohn.Forte@Sun.COM 			if (++(w->worker_queue_depth) >
35047836SJohn.Forte@Sun.COM 			    w->worker_max_qdepth_pu) {
35057836SJohn.Forte@Sun.COM 				w->worker_max_qdepth_pu = w->worker_queue_depth;
35067836SJohn.Forte@Sun.COM 			}
35077836SJohn.Forte@Sun.COM 			if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
35087836SJohn.Forte@Sun.COM 				cv_signal(&w->worker_cv);
35097836SJohn.Forte@Sun.COM 		}
35107836SJohn.Forte@Sun.COM 	}
35117836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
35127836SJohn.Forte@Sun.COM 
35137836SJohn.Forte@Sun.COM 	if (free_it) {
35147836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
35157836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
35167836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
35179435STim.Szeto@Sun.COM 			stmf_update_kstat_lu_q(task, kstat_runq_exit);
35189435STim.Szeto@Sun.COM 			stmf_update_kstat_lport_q(task, kstat_runq_exit);
35197836SJohn.Forte@Sun.COM 			stmf_task_free(task);
35207836SJohn.Forte@Sun.COM 		}
35217836SJohn.Forte@Sun.COM 	}
35227836SJohn.Forte@Sun.COM }
35237836SJohn.Forte@Sun.COM 
35247836SJohn.Forte@Sun.COM stmf_status_t
35257836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
35267836SJohn.Forte@Sun.COM {
35278859STim.Szeto@Sun.COM 	DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task);
35288859STim.Szeto@Sun.COM 
35297836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
35308662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
35317836SJohn.Forte@Sun.COM 	if (ioflags & STMF_IOF_LU_DONE) {
35327836SJohn.Forte@Sun.COM 		uint32_t new, old;
35337836SJohn.Forte@Sun.COM 		do {
35347836SJohn.Forte@Sun.COM 			new = old = itask->itask_flags;
35357836SJohn.Forte@Sun.COM 			if (new & ITASK_BEING_ABORTED)
35367836SJohn.Forte@Sun.COM 				return (STMF_ABORTED);
35377836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_LU;
35387836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
35397836SJohn.Forte@Sun.COM 	}
35407836SJohn.Forte@Sun.COM 
35417836SJohn.Forte@Sun.COM 	if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) {
35427836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
35437836SJohn.Forte@Sun.COM 	}
35447836SJohn.Forte@Sun.COM 
35457836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_BEING_ABORTED)
35467836SJohn.Forte@Sun.COM 		return (STMF_ABORTED);
35477836SJohn.Forte@Sun.COM 
35487836SJohn.Forte@Sun.COM 	if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) {
35497836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
35507836SJohn.Forte@Sun.COM 		task->task_resid = 0;
35517836SJohn.Forte@Sun.COM 	} else if (task->task_cmd_xfer_length >
35527836SJohn.Forte@Sun.COM 	    task->task_expected_xfer_length) {
35537836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_OVER;
35547836SJohn.Forte@Sun.COM 		task->task_resid = task->task_cmd_xfer_length -
35558662SJordan.Vaughan@Sun.com 		    task->task_expected_xfer_length;
35567836SJohn.Forte@Sun.COM 	} else if (task->task_nbytes_transferred <
35578662SJordan.Vaughan@Sun.com 	    task->task_expected_xfer_length) {
35587836SJohn.Forte@Sun.COM 		task->task_status_ctrl = TASK_SCTRL_UNDER;
35597836SJohn.Forte@Sun.COM 		task->task_resid = task->task_expected_xfer_length -
35608662SJordan.Vaughan@Sun.com 		    task->task_nbytes_transferred;
35617836SJohn.Forte@Sun.COM 	} else {
35627836SJohn.Forte@Sun.COM 		task->task_status_ctrl = 0;
35637836SJohn.Forte@Sun.COM 		task->task_resid = 0;
35647836SJohn.Forte@Sun.COM 	}
35657836SJohn.Forte@Sun.COM 	return (task->task_lport->lport_send_status(task, ioflags));
35667836SJohn.Forte@Sun.COM }
35677836SJohn.Forte@Sun.COM 
35687836SJohn.Forte@Sun.COM void
35697836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof)
35707836SJohn.Forte@Sun.COM {
35717836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
35727836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
35737836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
35747836SJohn.Forte@Sun.COM 	uint32_t new, old;
35757836SJohn.Forte@Sun.COM 	uint8_t free_it, queue_it;
35767836SJohn.Forte@Sun.COM 
35777836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
35787836SJohn.Forte@Sun.COM 	do {
35797836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
35807836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
35817836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
35827836SJohn.Forte@Sun.COM 			return;
35837836SJohn.Forte@Sun.COM 		}
35847836SJohn.Forte@Sun.COM 		free_it = 0;
35857836SJohn.Forte@Sun.COM 		if (iof & STMF_IOF_LPORT_DONE) {
35867836SJohn.Forte@Sun.COM 			new &= ~ITASK_KNOWN_TO_TGT_PORT;
35877836SJohn.Forte@Sun.COM 			free_it = 1;
35887836SJohn.Forte@Sun.COM 		}
35897836SJohn.Forte@Sun.COM 		/*
35907836SJohn.Forte@Sun.COM 		 * If the task is known to LU then queue it. But if
35917836SJohn.Forte@Sun.COM 		 * it is already queued (multiple completions) then
35927836SJohn.Forte@Sun.COM 		 * just update the buffer information by grabbing the
35937836SJohn.Forte@Sun.COM 		 * worker lock. If the task is not known to LU,
35947836SJohn.Forte@Sun.COM 		 * completed/aborted, then see if we need to
35957836SJohn.Forte@Sun.COM 		 * free this task.
35967836SJohn.Forte@Sun.COM 		 */
35977836SJohn.Forte@Sun.COM 		if (old & ITASK_KNOWN_TO_LU) {
35987836SJohn.Forte@Sun.COM 			free_it = 0;
35997836SJohn.Forte@Sun.COM 			queue_it = 1;
36007836SJohn.Forte@Sun.COM 			if (old & ITASK_IN_WORKER_QUEUE) {
36017836SJohn.Forte@Sun.COM 				cmn_err(CE_PANIC, "status completion received"
36027836SJohn.Forte@Sun.COM 				    " when task is already in worker queue "
36037836SJohn.Forte@Sun.COM 				    " task = %p", (void *)task);
36047836SJohn.Forte@Sun.COM 			}
36057836SJohn.Forte@Sun.COM 			new |= ITASK_IN_WORKER_QUEUE;
36067836SJohn.Forte@Sun.COM 		} else {
36077836SJohn.Forte@Sun.COM 			queue_it = 0;
36087836SJohn.Forte@Sun.COM 		}
36097836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
36107836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
36117836SJohn.Forte@Sun.COM 
36129435STim.Szeto@Sun.COM 	stmf_update_kstat_lu_q(task, kstat_runq_exit);
36139435STim.Szeto@Sun.COM 	stmf_update_kstat_lport_q(task, kstat_runq_exit);
36149435STim.Szeto@Sun.COM 
36157836SJohn.Forte@Sun.COM 	if (queue_it) {
36167836SJohn.Forte@Sun.COM 		ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
36177836SJohn.Forte@Sun.COM 		itask->itask_cmd_stack[itask->itask_ncmds++] =
36187836SJohn.Forte@Sun.COM 		    ITASK_CMD_STATUS_DONE;
36197836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
36207836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
36217836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
36227836SJohn.Forte@Sun.COM 		} else {
36237836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
36247836SJohn.Forte@Sun.COM 		}
36257836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
36267836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
36277836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
36287836SJohn.Forte@Sun.COM 		}
36297836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
36307836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
36317836SJohn.Forte@Sun.COM 	}
36327836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
36337836SJohn.Forte@Sun.COM 
36347836SJohn.Forte@Sun.COM 	if (free_it) {
36357836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
36367836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
36377836SJohn.Forte@Sun.COM 		    ITASK_BEING_ABORTED)) == 0) {
36387836SJohn.Forte@Sun.COM 			stmf_task_free(task);
36397836SJohn.Forte@Sun.COM 		} else {
36407836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "LU is done with the task but LPORT "
36417836SJohn.Forte@Sun.COM 			    " is not done, itask %p", (void *)itask);
36427836SJohn.Forte@Sun.COM 		}
36437836SJohn.Forte@Sun.COM 	}
36447836SJohn.Forte@Sun.COM }
36457836SJohn.Forte@Sun.COM 
36467836SJohn.Forte@Sun.COM void
36477836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task)
36487836SJohn.Forte@Sun.COM {
36497836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
36508662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
36517836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
36527836SJohn.Forte@Sun.COM 	uint32_t new, old;
36537836SJohn.Forte@Sun.COM 
36547836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
36557836SJohn.Forte@Sun.COM 	do {
36567836SJohn.Forte@Sun.COM 		new = old = itask->itask_flags;
36577836SJohn.Forte@Sun.COM 		if (old & ITASK_BEING_ABORTED) {
36587836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
36597836SJohn.Forte@Sun.COM 			return;
36607836SJohn.Forte@Sun.COM 		}
36617836SJohn.Forte@Sun.COM 		if (old & ITASK_IN_WORKER_QUEUE) {
36627836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "task_lu_done received"
36637836SJohn.Forte@Sun.COM 			    " when task is in worker queue "
36647836SJohn.Forte@Sun.COM 			    " task = %p", (void *)task);
36657836SJohn.Forte@Sun.COM 		}
36667836SJohn.Forte@Sun.COM 		new &= ~ITASK_KNOWN_TO_LU;
36677836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
36687836SJohn.Forte@Sun.COM 
36697836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
36707836SJohn.Forte@Sun.COM 
36717836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
36727836SJohn.Forte@Sun.COM 	    ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
36737836SJohn.Forte@Sun.COM 	    ITASK_BEING_ABORTED)) == 0) {
36747836SJohn.Forte@Sun.COM 		stmf_task_free(task);
36757836SJohn.Forte@Sun.COM 	} else {
36767836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but "
36777836SJohn.Forte@Sun.COM 		    " the task is still not done, task = %p", (void *)task);
36787836SJohn.Forte@Sun.COM 	}
36797836SJohn.Forte@Sun.COM }
36807836SJohn.Forte@Sun.COM 
36817836SJohn.Forte@Sun.COM void
36827836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s)
36837836SJohn.Forte@Sun.COM {
36847836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
36857836SJohn.Forte@Sun.COM 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
36867836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
36877836SJohn.Forte@Sun.COM 	uint32_t old, new;
36887836SJohn.Forte@Sun.COM 
36897836SJohn.Forte@Sun.COM 	do {
36907836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
36917836SJohn.Forte@Sun.COM 		if ((old & ITASK_BEING_ABORTED) ||
36927836SJohn.Forte@Sun.COM 		    ((old & (ITASK_KNOWN_TO_TGT_PORT |
36937836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU)) == 0)) {
36947836SJohn.Forte@Sun.COM 			return;
36957836SJohn.Forte@Sun.COM 		}
36967836SJohn.Forte@Sun.COM 		new |= ITASK_BEING_ABORTED;
36977836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
36987836SJohn.Forte@Sun.COM 	task->task_completion_status = s;
36997836SJohn.Forte@Sun.COM 	itask->itask_start_time = ddi_get_lbolt();
37007836SJohn.Forte@Sun.COM 
37017836SJohn.Forte@Sun.COM 	if (((w = itask->itask_worker) == NULL) ||
37027836SJohn.Forte@Sun.COM 	    (itask->itask_flags & ITASK_IN_TRANSITION)) {
37037836SJohn.Forte@Sun.COM 		return;
37047836SJohn.Forte@Sun.COM 	}
37057836SJohn.Forte@Sun.COM 
37067836SJohn.Forte@Sun.COM 	/* Queue it and get out */
37077836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
37087836SJohn.Forte@Sun.COM 	if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) {
37097836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
37107836SJohn.Forte@Sun.COM 		return;
37117836SJohn.Forte@Sun.COM 	}
37127836SJohn.Forte@Sun.COM 	atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
37137836SJohn.Forte@Sun.COM 	itask->itask_worker_next = NULL;
37147836SJohn.Forte@Sun.COM 	if (w->worker_task_tail) {
37157836SJohn.Forte@Sun.COM 		w->worker_task_tail->itask_worker_next = itask;
37167836SJohn.Forte@Sun.COM 	} else {
37177836SJohn.Forte@Sun.COM 		w->worker_task_head = itask;
37187836SJohn.Forte@Sun.COM 	}
37197836SJohn.Forte@Sun.COM 	w->worker_task_tail = itask;
37207836SJohn.Forte@Sun.COM 	if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
37217836SJohn.Forte@Sun.COM 		w->worker_max_qdepth_pu = w->worker_queue_depth;
37227836SJohn.Forte@Sun.COM 	}
37237836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
37247836SJohn.Forte@Sun.COM 		cv_signal(&w->worker_cv);
37257836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
37267836SJohn.Forte@Sun.COM }
37277836SJohn.Forte@Sun.COM 
37287836SJohn.Forte@Sun.COM void
37297836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg)
37307836SJohn.Forte@Sun.COM {
37317836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = NULL;
37327836SJohn.Forte@Sun.COM 	uint32_t old, new, f, rf;
37337836SJohn.Forte@Sun.COM 
37348859STim.Szeto@Sun.COM 	DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task,
37358859STim.Szeto@Sun.COM 	    stmf_status_t, s);
37368859STim.Szeto@Sun.COM 
37377836SJohn.Forte@Sun.COM 	switch (abort_cmd) {
37387836SJohn.Forte@Sun.COM 	case STMF_QUEUE_ABORT_LU:
37397836SJohn.Forte@Sun.COM 		stmf_task_lu_killall((stmf_lu_t *)arg, task, s);
37407836SJohn.Forte@Sun.COM 		return;
37417836SJohn.Forte@Sun.COM 	case STMF_QUEUE_TASK_ABORT:
37427836SJohn.Forte@Sun.COM 		stmf_queue_task_for_abort(task, s);
37437836SJohn.Forte@Sun.COM 		return;
37447836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LPORT:
37457836SJohn.Forte@Sun.COM 		rf = ITASK_TGT_PORT_ABORT_CALLED;
37467836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_TGT_PORT;
37477836SJohn.Forte@Sun.COM 		break;
37487836SJohn.Forte@Sun.COM 	case STMF_REQUEUE_TASK_ABORT_LU:
37497836SJohn.Forte@Sun.COM 		rf = ITASK_LU_ABORT_CALLED;
37507836SJohn.Forte@Sun.COM 		f = ITASK_KNOWN_TO_LU;
37517836SJohn.Forte@Sun.COM 		break;
37527836SJohn.Forte@Sun.COM 	default:
37537836SJohn.Forte@Sun.COM 		return;
37547836SJohn.Forte@Sun.COM 	}
37557836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
37567836SJohn.Forte@Sun.COM 	f |= ITASK_BEING_ABORTED | rf;
37577836SJohn.Forte@Sun.COM 	do {
37587836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
37597836SJohn.Forte@Sun.COM 		if ((old & f) != f) {
37607836SJohn.Forte@Sun.COM 			return;
37617836SJohn.Forte@Sun.COM 		}
37627836SJohn.Forte@Sun.COM 		new &= ~rf;
37637836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
37647836SJohn.Forte@Sun.COM }
37657836SJohn.Forte@Sun.COM 
37667836SJohn.Forte@Sun.COM void
37677836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
37687836SJohn.Forte@Sun.COM {
37697836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
37707836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
37717836SJohn.Forte@Sun.COM 	unsigned long long	st;
37727836SJohn.Forte@Sun.COM 
37737836SJohn.Forte@Sun.COM 	st = s;	/* gcc fix */
37747836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
37757836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37767836SJohn.Forte@Sun.COM 		    "task %p, lu failed to abort ret=%llx", (void *)task, st);
37777836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LU_DONE) == 0) {
37787836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
37797836SJohn.Forte@Sun.COM 		    "Task aborted but LU is not finished, task ="
37807836SJohn.Forte@Sun.COM 		    "%p, s=%llx, iof=%x", (void *)task, st, iof);
37817836SJohn.Forte@Sun.COM 	} else {
37827836SJohn.Forte@Sun.COM 		/*
37837836SJohn.Forte@Sun.COM 		 * LU abort successfully
37847836SJohn.Forte@Sun.COM 		 */
37857836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU);
37867836SJohn.Forte@Sun.COM 		return;
37877836SJohn.Forte@Sun.COM 	}
37887836SJohn.Forte@Sun.COM 
37897836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
37907836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 1, info);
37917836SJohn.Forte@Sun.COM }
37927836SJohn.Forte@Sun.COM 
37937836SJohn.Forte@Sun.COM void
37947836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
37957836SJohn.Forte@Sun.COM {
37967836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
37977836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
37987836SJohn.Forte@Sun.COM 	unsigned long long	st;
37997836SJohn.Forte@Sun.COM 
38007836SJohn.Forte@Sun.COM 	st = s;
38017836SJohn.Forte@Sun.COM 	if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
38027836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
38037836SJohn.Forte@Sun.COM 		    "task %p, tgt port failed to abort ret=%llx", (void *)task,
38047836SJohn.Forte@Sun.COM 		    st);
38057836SJohn.Forte@Sun.COM 	} else if ((iof & STMF_IOF_LPORT_DONE) == 0) {
38067836SJohn.Forte@Sun.COM 		(void) snprintf(info, STMF_CHANGE_INFO_LEN,
38077836SJohn.Forte@Sun.COM 		    "Task aborted but tgt port is not finished, "
38087836SJohn.Forte@Sun.COM 		    "task=%p, s=%llx, iof=%x", (void *)task, st, iof);
38097836SJohn.Forte@Sun.COM 	} else {
38107836SJohn.Forte@Sun.COM 		/*
38117836SJohn.Forte@Sun.COM 		 * LU abort successfully
38127836SJohn.Forte@Sun.COM 		 */
38137836SJohn.Forte@Sun.COM 		atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT);
38147836SJohn.Forte@Sun.COM 		return;
38157836SJohn.Forte@Sun.COM 	}
38167836SJohn.Forte@Sun.COM 
38177836SJohn.Forte@Sun.COM 	info[STMF_CHANGE_INFO_LEN - 1] = 0;
38187836SJohn.Forte@Sun.COM 	stmf_abort_task_offline(task, 0, info);
38197836SJohn.Forte@Sun.COM }
38207836SJohn.Forte@Sun.COM 
38217836SJohn.Forte@Sun.COM stmf_status_t
38227836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout)
38237836SJohn.Forte@Sun.COM {
38247836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
38257836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
38267836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
38277836SJohn.Forte@Sun.COM 	int i;
38287836SJohn.Forte@Sun.COM 
38297836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU);
38307836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
38317836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
38327836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
38337836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
38347836SJohn.Forte@Sun.COM 	}
38357836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
38367836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) {
38377836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
38387836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
38397836SJohn.Forte@Sun.COM 		}
38407836SJohn.Forte@Sun.COM 	}
38417836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU;
38427836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
38437836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
38447836SJohn.Forte@Sun.COM 	} else {
38457836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
38467836SJohn.Forte@Sun.COM 		if (t == 0)
38477836SJohn.Forte@Sun.COM 			t = 1;
38487836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
38497836SJohn.Forte@Sun.COM 	}
38507836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
38517836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
38527836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
38537836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
38547836SJohn.Forte@Sun.COM 		} else {
38557836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
38567836SJohn.Forte@Sun.COM 		}
38577836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
38587836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
38597836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
38607836SJohn.Forte@Sun.COM 		}
38617836SJohn.Forte@Sun.COM 		atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
38627836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
38637836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
38647836SJohn.Forte@Sun.COM 	}
38657836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
38667836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
38677836SJohn.Forte@Sun.COM }
38687836SJohn.Forte@Sun.COM 
38697836SJohn.Forte@Sun.COM stmf_status_t
38707836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout)
38717836SJohn.Forte@Sun.COM {
38727836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
38737836SJohn.Forte@Sun.COM 	    task->task_stmf_private;
38747836SJohn.Forte@Sun.COM 	stmf_worker_t *w = itask->itask_worker;
38757836SJohn.Forte@Sun.COM 	int i;
38767836SJohn.Forte@Sun.COM 
38777836SJohn.Forte@Sun.COM 	ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT);
38787836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
38797836SJohn.Forte@Sun.COM 	if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
38807836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
38817836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
38827836SJohn.Forte@Sun.COM 	}
38837836SJohn.Forte@Sun.COM 	for (i = 0; i < itask->itask_ncmds; i++) {
38847836SJohn.Forte@Sun.COM 		if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) {
38857836SJohn.Forte@Sun.COM 			mutex_exit(&w->worker_lock);
38867836SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
38877836SJohn.Forte@Sun.COM 		}
38887836SJohn.Forte@Sun.COM 	}
38897836SJohn.Forte@Sun.COM 	itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT;
38907836SJohn.Forte@Sun.COM 	if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
38917836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + 1;
38927836SJohn.Forte@Sun.COM 	} else {
38937836SJohn.Forte@Sun.COM 		clock_t t = drv_usectohz(timeout * 1000);
38947836SJohn.Forte@Sun.COM 		if (t == 0)
38957836SJohn.Forte@Sun.COM 			t = 1;
38967836SJohn.Forte@Sun.COM 		itask->itask_poll_timeout = ddi_get_lbolt() + t;
38977836SJohn.Forte@Sun.COM 	}
38987836SJohn.Forte@Sun.COM 	if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
38997836SJohn.Forte@Sun.COM 		itask->itask_worker_next = NULL;
39007836SJohn.Forte@Sun.COM 		if (w->worker_task_tail) {
39017836SJohn.Forte@Sun.COM 			w->worker_task_tail->itask_worker_next = itask;
39027836SJohn.Forte@Sun.COM 		} else {
39037836SJohn.Forte@Sun.COM 			w->worker_task_head = itask;
39047836SJohn.Forte@Sun.COM 		}
39057836SJohn.Forte@Sun.COM 		w->worker_task_tail = itask;
39067836SJohn.Forte@Sun.COM 		if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
39077836SJohn.Forte@Sun.COM 			w->worker_max_qdepth_pu = w->worker_queue_depth;
39087836SJohn.Forte@Sun.COM 		}
39097836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
39107836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
39117836SJohn.Forte@Sun.COM 	}
39127836SJohn.Forte@Sun.COM 	mutex_exit(&w->worker_lock);
39137836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
39147836SJohn.Forte@Sun.COM }
39157836SJohn.Forte@Sun.COM 
39167836SJohn.Forte@Sun.COM void
39177836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task)
39187836SJohn.Forte@Sun.COM {
39197836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t	*itask = TASK_TO_ITASK(task);
39207836SJohn.Forte@Sun.COM 	stmf_lu_t		*lu;
39217836SJohn.Forte@Sun.COM 	stmf_local_port_t	*lport;
39227836SJohn.Forte@Sun.COM 	unsigned long long	 ret;
39237836SJohn.Forte@Sun.COM 	uint32_t		 old, new;
39247836SJohn.Forte@Sun.COM 	uint8_t			 call_lu_abort, call_port_abort;
39257836SJohn.Forte@Sun.COM 	char			 info[STMF_CHANGE_INFO_LEN];
39267836SJohn.Forte@Sun.COM 
39277836SJohn.Forte@Sun.COM 	lu = task->task_lu;
39287836SJohn.Forte@Sun.COM 	lport = task->task_lport;
39297836SJohn.Forte@Sun.COM 	do {
39307836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
39317836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) ==
39327836SJohn.Forte@Sun.COM 		    ITASK_KNOWN_TO_LU) {
39337836SJohn.Forte@Sun.COM 			new |= ITASK_LU_ABORT_CALLED;
39347836SJohn.Forte@Sun.COM 			call_lu_abort = 1;
39357836SJohn.Forte@Sun.COM 		} else {
39367836SJohn.Forte@Sun.COM 			call_lu_abort = 0;
39377836SJohn.Forte@Sun.COM 		}
39387836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
39397836SJohn.Forte@Sun.COM 
39407836SJohn.Forte@Sun.COM 	if (call_lu_abort) {
39417836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) {
39427836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
39437836SJohn.Forte@Sun.COM 		} else {
39447836SJohn.Forte@Sun.COM 			ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
39457836SJohn.Forte@Sun.COM 		}
39467836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
39477836SJohn.Forte@Sun.COM 			stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE);
39487836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
39497836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
39507836SJohn.Forte@Sun.COM 			    ~ITASK_LU_ABORT_CALLED);
39517836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
39527836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39537836SJohn.Forte@Sun.COM 			    "Abort failed by LU %p, ret %llx", (void *)lu, ret);
39547836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39557836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 1, info);
39567836SJohn.Forte@Sun.COM 		}
39577836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_LU) {
39587836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
39597836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lu->lu_abort_timeout?
39607836SJohn.Forte@Sun.COM 		    lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) {
39617836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39627836SJohn.Forte@Sun.COM 			    "lu abort timed out");
39637836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39647836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 1, info);
39657836SJohn.Forte@Sun.COM 		}
39667836SJohn.Forte@Sun.COM 	}
39677836SJohn.Forte@Sun.COM 
39687836SJohn.Forte@Sun.COM 	do {
39697836SJohn.Forte@Sun.COM 		old = new = itask->itask_flags;
39707836SJohn.Forte@Sun.COM 		if ((old & (ITASK_KNOWN_TO_TGT_PORT |
39717836SJohn.Forte@Sun.COM 		    ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) {
39727836SJohn.Forte@Sun.COM 			new |= ITASK_TGT_PORT_ABORT_CALLED;
39737836SJohn.Forte@Sun.COM 			call_port_abort = 1;
39747836SJohn.Forte@Sun.COM 		} else {
39757836SJohn.Forte@Sun.COM 			call_port_abort = 0;
39767836SJohn.Forte@Sun.COM 		}
39777836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
39787836SJohn.Forte@Sun.COM 	if (call_port_abort) {
39798662SJordan.Vaughan@Sun.com 		ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0);
39807836SJohn.Forte@Sun.COM 		if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
39817836SJohn.Forte@Sun.COM 			stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE);
39827836SJohn.Forte@Sun.COM 		} else if (ret == STMF_BUSY) {
39837836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
39847836SJohn.Forte@Sun.COM 			    ~ITASK_TGT_PORT_ABORT_CALLED);
39857836SJohn.Forte@Sun.COM 		} else if (ret != STMF_SUCCESS) {
39867836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39877836SJohn.Forte@Sun.COM 			    "Abort failed by tgt port %p ret %llx",
39887836SJohn.Forte@Sun.COM 			    (void *)lport, ret);
39897836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
39907836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(task, 0, info);
39917836SJohn.Forte@Sun.COM 		}
39927836SJohn.Forte@Sun.COM 	} else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) {
39937836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > (itask->itask_start_time +
39947836SJohn.Forte@Sun.COM 		    STMF_SEC2TICK(lport->lport_abort_timeout?
39957836SJohn.Forte@Sun.COM 		    lport->lport_abort_timeout :
39967836SJohn.Forte@Sun.COM 		    ITASK_DEFAULT_ABORT_TIMEOUT))) {
39977836SJohn.Forte@Sun.COM 			(void) snprintf(info, STMF_CHANGE_INFO_LEN,
39987836SJohn.Forte@Sun.COM 			    "lport abort timed out");
39997836SJohn.Forte@Sun.COM 			info[STMF_CHANGE_INFO_LEN - 1] = 0;
40007836SJohn.Forte@Sun.COM 			stmf_abort_task_offline(itask->itask_task, 0, info);
40017836SJohn.Forte@Sun.COM 		}
40027836SJohn.Forte@Sun.COM 	}
40037836SJohn.Forte@Sun.COM }
40047836SJohn.Forte@Sun.COM 
40057836SJohn.Forte@Sun.COM stmf_status_t
40067836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg)
40077836SJohn.Forte@Sun.COM {
40087836SJohn.Forte@Sun.COM 	stmf_status_t			ret;
40097836SJohn.Forte@Sun.COM 	stmf_i_lu_t			*ilu;
40107836SJohn.Forte@Sun.COM 	stmf_i_local_port_t		*ilport;
40117836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
40127836SJohn.Forte@Sun.COM 
40137836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
40147836SJohn.Forte@Sun.COM 	ret = STMF_INVALID_ARG;
40157836SJohn.Forte@Sun.COM 	if (cmd & STMF_CMD_LU_OP) {
40167836SJohn.Forte@Sun.COM 		ilu = stmf_lookup_lu((stmf_lu_t *)obj);
40177836SJohn.Forte@Sun.COM 		if (ilu == NULL) {
40187836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40197836SJohn.Forte@Sun.COM 		}
40208859STim.Szeto@Sun.COM 		DTRACE_PROBE3(lu__state__change,
40218859STim.Szeto@Sun.COM 		    stmf_lu_t *, ilu->ilu_lu,
40228859STim.Szeto@Sun.COM 		    int, cmd, stmf_state_change_info_t *, ssci);
40237836SJohn.Forte@Sun.COM 	} else if (cmd & STMF_CMD_LPORT_OP) {
40247836SJohn.Forte@Sun.COM 		ilport = stmf_lookup_lport((stmf_local_port_t *)obj);
40257836SJohn.Forte@Sun.COM 		if (ilport == NULL) {
40267836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40277836SJohn.Forte@Sun.COM 		}
40288859STim.Szeto@Sun.COM 		DTRACE_PROBE3(lport__state__change,
40298859STim.Szeto@Sun.COM 		    stmf_local_port_t *, ilport->ilport_lport,
40308859STim.Szeto@Sun.COM 		    int, cmd, stmf_state_change_info_t *, ssci);
40317836SJohn.Forte@Sun.COM 	} else {
40327836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
40337836SJohn.Forte@Sun.COM 	}
40347836SJohn.Forte@Sun.COM 
40357836SJohn.Forte@Sun.COM 	switch (cmd) {
40367836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE:
40377836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_ONLINE) {
40387836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
40397836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40407836SJohn.Forte@Sun.COM 		}
40417836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINE) {
40427836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40437836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40447836SJohn.Forte@Sun.COM 		}
40457836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_ONLINING;
40467836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40477836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
40487836SJohn.Forte@Sun.COM 		break;
40497836SJohn.Forte@Sun.COM 
40507836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_ONLINE_COMPLETE:
40517836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINING) {
40527836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40537836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40547836SJohn.Forte@Sun.COM 		}
40557836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
40567836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
40577836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
40587836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
40597836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
40607836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_ONLINE_COMPLETE, arg);
40617836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
40627836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
40637836SJohn.Forte@Sun.COM 		} else {
40647836SJohn.Forte@Sun.COM 			/* XXX: should throw a meesage an record more data */
40657836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
40667836SJohn.Forte@Sun.COM 		}
40677836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
40687836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
40697836SJohn.Forte@Sun.COM 
40707836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE:
40717836SJohn.Forte@Sun.COM 		if (ilu->ilu_state == STMF_STATE_OFFLINE) {
40727836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
40737836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40747836SJohn.Forte@Sun.COM 		}
40757836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_ONLINE) {
40767836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40777836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40787836SJohn.Forte@Sun.COM 		}
40797836SJohn.Forte@Sun.COM 		ilu->ilu_state = STMF_STATE_OFFLINING;
40807836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
40817836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
40827836SJohn.Forte@Sun.COM 		break;
40837836SJohn.Forte@Sun.COM 
40847836SJohn.Forte@Sun.COM 	case STMF_CMD_LU_OFFLINE_COMPLETE:
40857836SJohn.Forte@Sun.COM 		if (ilu->ilu_state != STMF_STATE_OFFLINING) {
40867836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
40877836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
40887836SJohn.Forte@Sun.COM 		}
40897836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
40907836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
40917836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_OFFLINE;
40927836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
40937836SJohn.Forte@Sun.COM 			((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
40947836SJohn.Forte@Sun.COM 			    STMF_ACK_LU_OFFLINE_COMPLETE, arg);
40957836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
40967836SJohn.Forte@Sun.COM 		} else {
40977836SJohn.Forte@Sun.COM 			ilu->ilu_state = STMF_STATE_ONLINE;
40987836SJohn.Forte@Sun.COM 			stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
40997836SJohn.Forte@Sun.COM 		}
41007836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41017836SJohn.Forte@Sun.COM 		break;
41027836SJohn.Forte@Sun.COM 
41037836SJohn.Forte@Sun.COM 	/*
41047836SJohn.Forte@Sun.COM 	 * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online.
41057836SJohn.Forte@Sun.COM 	 * It's related with hardware disable/enable.
41067836SJohn.Forte@Sun.COM 	 */
41077836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE:
41087836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_ONLINE) {
41097836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
41107836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41117836SJohn.Forte@Sun.COM 		}
41127836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINE) {
41137836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41147836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41157836SJohn.Forte@Sun.COM 		}
41167836SJohn.Forte@Sun.COM 
41177836SJohn.Forte@Sun.COM 		/*
41187836SJohn.Forte@Sun.COM 		 * Only user request can recover the port from the
41197836SJohn.Forte@Sun.COM 		 * FORCED_OFFLINE state
41207836SJohn.Forte@Sun.COM 		 */
41217836SJohn.Forte@Sun.COM 		if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) {
41227836SJohn.Forte@Sun.COM 			if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) {
41237836SJohn.Forte@Sun.COM 				ret = STMF_FAILURE;
41247836SJohn.Forte@Sun.COM 				goto stmf_ctl_lock_exit;
41257836SJohn.Forte@Sun.COM 			}
41267836SJohn.Forte@Sun.COM 		}
41277836SJohn.Forte@Sun.COM 
41287836SJohn.Forte@Sun.COM 		/*
41297836SJohn.Forte@Sun.COM 		 * Avoid too frequent request to online
41307836SJohn.Forte@Sun.COM 		 */
41317836SJohn.Forte@Sun.COM 		if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
41327836SJohn.Forte@Sun.COM 			ilport->ilport_online_times = 0;
41337836SJohn.Forte@Sun.COM 			ilport->ilport_avg_interval = 0;
41347836SJohn.Forte@Sun.COM 		}
41357836SJohn.Forte@Sun.COM 		if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) &&
41367836SJohn.Forte@Sun.COM 		    (ilport->ilport_online_times >= 4)) {
41377836SJohn.Forte@Sun.COM 			ret = STMF_FAILURE;
41387836SJohn.Forte@Sun.COM 			ilport->ilport_flags |= ILPORT_FORCED_OFFLINE;
41397836SJohn.Forte@Sun.COM 			stmf_trace(NULL, "stmf_ctl: too frequent request to "
41407836SJohn.Forte@Sun.COM 			    "online the port");
41417836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "stmf_ctl: too frequent request to "
41427836SJohn.Forte@Sun.COM 			    "online the port, set FORCED_OFFLINE now");
41437836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41447836SJohn.Forte@Sun.COM 		}
41457836SJohn.Forte@Sun.COM 		if (ilport->ilport_online_times > 0) {
41467836SJohn.Forte@Sun.COM 			if (ilport->ilport_online_times == 1) {
41477836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval = ddi_get_lbolt() -
41487836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock;
41497836SJohn.Forte@Sun.COM 			} else {
41507836SJohn.Forte@Sun.COM 				ilport->ilport_avg_interval =
41517836SJohn.Forte@Sun.COM 				    (ilport->ilport_avg_interval +
41527836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() -
41537836SJohn.Forte@Sun.COM 				    ilport->ilport_last_online_clock) >> 1;
41547836SJohn.Forte@Sun.COM 			}
41557836SJohn.Forte@Sun.COM 		}
41567836SJohn.Forte@Sun.COM 		ilport->ilport_last_online_clock = ddi_get_lbolt();
41577836SJohn.Forte@Sun.COM 		ilport->ilport_online_times++;
41587836SJohn.Forte@Sun.COM 
41597836SJohn.Forte@Sun.COM 		/*
41607836SJohn.Forte@Sun.COM 		 * Submit online service request
41617836SJohn.Forte@Sun.COM 		 */
41627836SJohn.Forte@Sun.COM 		ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE;
41637836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_ONLINING;
41647836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41657836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
41667836SJohn.Forte@Sun.COM 		break;
41677836SJohn.Forte@Sun.COM 
41687836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE_COMPLETE:
41697836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINING) {
41707836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41717836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41727836SJohn.Forte@Sun.COM 		}
41737836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
41747836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
41757836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
41767836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
41777836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
41787836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
41797836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_ONLINE_COMPLETE, arg);
41807836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
41817836SJohn.Forte@Sun.COM 		} else {
41827836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
41837836SJohn.Forte@Sun.COM 		}
41847836SJohn.Forte@Sun.COM 		ret = STMF_SUCCESS;
41857836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
41867836SJohn.Forte@Sun.COM 
41877836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE:
41887836SJohn.Forte@Sun.COM 		if (ilport->ilport_state == STMF_STATE_OFFLINE) {
41897836SJohn.Forte@Sun.COM 			ret = STMF_ALREADY;
41907836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41917836SJohn.Forte@Sun.COM 		}
41927836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_ONLINE) {
41937836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
41947836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
41957836SJohn.Forte@Sun.COM 		}
41967836SJohn.Forte@Sun.COM 		ilport->ilport_state = STMF_STATE_OFFLINING;
41977836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
41987836SJohn.Forte@Sun.COM 		stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
41997836SJohn.Forte@Sun.COM 		break;
42007836SJohn.Forte@Sun.COM 
42017836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE_COMPLETE:
42027836SJohn.Forte@Sun.COM 		if (ilport->ilport_state != STMF_STATE_OFFLINING) {
42037836SJohn.Forte@Sun.COM 			ret = STMF_INVALID_ARG;
42047836SJohn.Forte@Sun.COM 			goto stmf_ctl_lock_exit;
42057836SJohn.Forte@Sun.COM 		}
42067836SJohn.Forte@Sun.COM 		if (((stmf_change_status_t *)arg)->st_completion_status ==
42077836SJohn.Forte@Sun.COM 		    STMF_SUCCESS) {
42087836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_OFFLINE;
42097836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
42107836SJohn.Forte@Sun.COM 			((stmf_local_port_t *)obj)->lport_ctl(
42117836SJohn.Forte@Sun.COM 			    (stmf_local_port_t *)obj,
42127836SJohn.Forte@Sun.COM 			    STMF_ACK_LPORT_OFFLINE_COMPLETE, arg);
42137836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
42147836SJohn.Forte@Sun.COM 		} else {
42157836SJohn.Forte@Sun.COM 			ilport->ilport_state = STMF_STATE_ONLINE;
42167836SJohn.Forte@Sun.COM 		}
42177836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
42187836SJohn.Forte@Sun.COM 		break;
42197836SJohn.Forte@Sun.COM 
42207836SJohn.Forte@Sun.COM 	default:
42217836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd);
42227836SJohn.Forte@Sun.COM 		ret = STMF_INVALID_ARG;
42237836SJohn.Forte@Sun.COM 		goto stmf_ctl_lock_exit;
42247836SJohn.Forte@Sun.COM 	}
42257836SJohn.Forte@Sun.COM 
42267836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
42277836SJohn.Forte@Sun.COM 
42287836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:;
42297836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
42307836SJohn.Forte@Sun.COM 	return (ret);
42317836SJohn.Forte@Sun.COM }
42327836SJohn.Forte@Sun.COM 
42337836SJohn.Forte@Sun.COM /* ARGSUSED */
42347836SJohn.Forte@Sun.COM stmf_status_t
42357836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
42367836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
42377836SJohn.Forte@Sun.COM {
42387836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
42397836SJohn.Forte@Sun.COM }
42407836SJohn.Forte@Sun.COM 
42417836SJohn.Forte@Sun.COM /* ARGSUSED */
42427836SJohn.Forte@Sun.COM stmf_status_t
42437836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
42447836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
42457836SJohn.Forte@Sun.COM {
42467836SJohn.Forte@Sun.COM 	uint32_t cl = SI_GET_CLASS(cmd);
42477836SJohn.Forte@Sun.COM 
42487836SJohn.Forte@Sun.COM 	if (cl == SI_STMF) {
42497836SJohn.Forte@Sun.COM 		return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep));
42507836SJohn.Forte@Sun.COM 	}
42517836SJohn.Forte@Sun.COM 	if (cl == SI_LPORT) {
42528662SJordan.Vaughan@Sun.com 		return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1,
42538662SJordan.Vaughan@Sun.com 		    arg2, buf, bufsizep));
42547836SJohn.Forte@Sun.COM 	} else if (cl == SI_LU) {
42558662SJordan.Vaughan@Sun.com 		return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf,
42568662SJordan.Vaughan@Sun.com 		    bufsizep));
42577836SJohn.Forte@Sun.COM 	}
42587836SJohn.Forte@Sun.COM 
42597836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
42607836SJohn.Forte@Sun.COM }
42617836SJohn.Forte@Sun.COM 
42627836SJohn.Forte@Sun.COM /*
42637836SJohn.Forte@Sun.COM  * Used by port providers. pwwn is 8 byte wwn, sdid is th devid used by
42647836SJohn.Forte@Sun.COM  * stmf to register local ports. The ident should have 20 bytes in buffer
42657836SJohn.Forte@Sun.COM  * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string.
42667836SJohn.Forte@Sun.COM  */
42677836SJohn.Forte@Sun.COM void
42687836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn,
42697836SJohn.Forte@Sun.COM     uint8_t protocol_id)
42707836SJohn.Forte@Sun.COM {
42717836SJohn.Forte@Sun.COM 	sdid->protocol_id = protocol_id;
42727836SJohn.Forte@Sun.COM 	sdid->piv = 1;
42737836SJohn.Forte@Sun.COM 	sdid->code_set = CODE_SET_ASCII;
42747836SJohn.Forte@Sun.COM 	sdid->association = ID_IS_TARGET_PORT;
42757836SJohn.Forte@Sun.COM 	sdid->ident_length = 20;
42767836SJohn.Forte@Sun.COM 	(void) sprintf((char *)sdid->ident,
42777836SJohn.Forte@Sun.COM 	    "wwn.%02X%02X%02X%02X%02X%02X%02X%02X",
42787836SJohn.Forte@Sun.COM 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
42797836SJohn.Forte@Sun.COM }
42807836SJohn.Forte@Sun.COM 
42817836SJohn.Forte@Sun.COM stmf_xfer_data_t *
42827836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data()
42837836SJohn.Forte@Sun.COM {
42847836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
42857836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport;
42867836SJohn.Forte@Sun.COM 	uint8_t *p;
42877836SJohn.Forte@Sun.COM 	uint32_t sz, asz, nports;
42887836SJohn.Forte@Sun.COM 
42897836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
42907836SJohn.Forte@Sun.COM 	/* The spec only allows for 255 ports to be reported */
42917836SJohn.Forte@Sun.COM 	nports = min(stmf_state.stmf_nlports, 255);
42927836SJohn.Forte@Sun.COM 	sz = (nports * 4) + 12;
42937836SJohn.Forte@Sun.COM 	asz = sz + sizeof (*xd) - 4;
42947836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
42957836SJohn.Forte@Sun.COM 	if (xd == NULL) {
42967836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
42977836SJohn.Forte@Sun.COM 		return (NULL);
42987836SJohn.Forte@Sun.COM 	}
42997836SJohn.Forte@Sun.COM 	xd->alloc_size = asz;
43007836SJohn.Forte@Sun.COM 	xd->size_left = sz;
43017836SJohn.Forte@Sun.COM 
43027836SJohn.Forte@Sun.COM 	p = xd->buf;
43037836SJohn.Forte@Sun.COM 
43047836SJohn.Forte@Sun.COM 	*((uint32_t *)p) = BE_32(sz - 4);
43057836SJohn.Forte@Sun.COM 	p += 4;
43067836SJohn.Forte@Sun.COM 	p[0] = 0x80;	/* PREF */
43077836SJohn.Forte@Sun.COM 	p[1] = 1;	/* AO_SUP */
43087836SJohn.Forte@Sun.COM 	p[7] = nports & 0xff;
43097836SJohn.Forte@Sun.COM 	p += 8;
43107836SJohn.Forte@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport && nports;
43117836SJohn.Forte@Sun.COM 	    nports++, ilport = ilport->ilport_next, p += 4) {
43127836SJohn.Forte@Sun.COM 		((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid);
43137836SJohn.Forte@Sun.COM 	}
43147836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
43157836SJohn.Forte@Sun.COM 
43167836SJohn.Forte@Sun.COM 	return (xd);
43177836SJohn.Forte@Sun.COM }
43187836SJohn.Forte@Sun.COM 
4319*9585STim.Szeto@Sun.COM struct scsi_devid_desc *
4320*9585STim.Szeto@Sun.COM stmf_scsilib_get_devid_desc(uint16_t rtpid)
4321*9585STim.Szeto@Sun.COM {
4322*9585STim.Szeto@Sun.COM 	scsi_devid_desc_t *devid = NULL;
4323*9585STim.Szeto@Sun.COM 	stmf_i_local_port_t *ilport;
4324*9585STim.Szeto@Sun.COM 
4325*9585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
4326*9585STim.Szeto@Sun.COM 
4327*9585STim.Szeto@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport;
4328*9585STim.Szeto@Sun.COM 	    ilport = ilport->ilport_next) {
4329*9585STim.Szeto@Sun.COM 		if (ilport->ilport_rtpid == rtpid) {
4330*9585STim.Szeto@Sun.COM 			scsi_devid_desc_t *id = ilport->ilport_lport->lport_id;
4331*9585STim.Szeto@Sun.COM 			uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 +
4332*9585STim.Szeto@Sun.COM 			    id->ident_length;
4333*9585STim.Szeto@Sun.COM 			devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz,
4334*9585STim.Szeto@Sun.COM 			    KM_NOSLEEP);
4335*9585STim.Szeto@Sun.COM 			if (devid != NULL) {
4336*9585STim.Szeto@Sun.COM 				bcopy(id, devid, id_sz);
4337*9585STim.Szeto@Sun.COM 			}
4338*9585STim.Szeto@Sun.COM 			break;
4339*9585STim.Szeto@Sun.COM 		}
4340*9585STim.Szeto@Sun.COM 	}
4341*9585STim.Szeto@Sun.COM 
4342*9585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
4343*9585STim.Szeto@Sun.COM 	return (devid);
4344*9585STim.Szeto@Sun.COM }
4345*9585STim.Szeto@Sun.COM 
4346*9585STim.Szeto@Sun.COM uint16_t
4347*9585STim.Szeto@Sun.COM stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid)
4348*9585STim.Szeto@Sun.COM {
4349*9585STim.Szeto@Sun.COM 	stmf_i_local_port_t	*ilport;
4350*9585STim.Szeto@Sun.COM 	scsi_devid_desc_t	*id;
4351*9585STim.Szeto@Sun.COM 	uint16_t		rtpid = 0;
4352*9585STim.Szeto@Sun.COM 
4353*9585STim.Szeto@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
4354*9585STim.Szeto@Sun.COM 	for (ilport = stmf_state.stmf_ilportlist; ilport;
4355*9585STim.Szeto@Sun.COM 	    ilport = ilport->ilport_next) {
4356*9585STim.Szeto@Sun.COM 		id = ilport->ilport_lport->lport_id;
4357*9585STim.Szeto@Sun.COM 		if ((devid->ident_length == id->ident_length) &&
4358*9585STim.Szeto@Sun.COM 		    (memcmp(devid->ident, id->ident, id->ident_length) == 0)) {
4359*9585STim.Szeto@Sun.COM 			rtpid = ilport->ilport_rtpid;
4360*9585STim.Szeto@Sun.COM 			break;
4361*9585STim.Szeto@Sun.COM 		}
4362*9585STim.Szeto@Sun.COM 	}
4363*9585STim.Szeto@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
4364*9585STim.Szeto@Sun.COM 	return (rtpid);
4365*9585STim.Szeto@Sun.COM }
43667836SJohn.Forte@Sun.COM 
43677836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0;
43687836SJohn.Forte@Sun.COM 
43697836SJohn.Forte@Sun.COM stmf_status_t
43707836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id)
43717836SJohn.Forte@Sun.COM {
43727836SJohn.Forte@Sun.COM 	uint8_t *p;
43737836SJohn.Forte@Sun.COM 	struct timeval32 timestamp32;
43747836SJohn.Forte@Sun.COM 	uint32_t *t = (uint32_t *)&timestamp32;
43757836SJohn.Forte@Sun.COM 	struct ether_addr mac;
43767836SJohn.Forte@Sun.COM 	uint8_t *e = (uint8_t *)&mac;
43777836SJohn.Forte@Sun.COM 
43787836SJohn.Forte@Sun.COM 	if (company_id == COMPANY_ID_NONE)
43797836SJohn.Forte@Sun.COM 		company_id = COMPANY_ID_SUN;
43807836SJohn.Forte@Sun.COM 
43817836SJohn.Forte@Sun.COM 	if (lu_id->ident_length != 0x10)
43827836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
43837836SJohn.Forte@Sun.COM 
43847836SJohn.Forte@Sun.COM 	p = (uint8_t *)lu_id;
43857836SJohn.Forte@Sun.COM 
43867836SJohn.Forte@Sun.COM 	atomic_add_16(&stmf_lu_id_gen_number, 1);
43877836SJohn.Forte@Sun.COM 
43887836SJohn.Forte@Sun.COM 	p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
43897836SJohn.Forte@Sun.COM 	p[4] = ((company_id >> 20) & 0xf) | 0x60;
43907836SJohn.Forte@Sun.COM 	p[5] = (company_id >> 12) & 0xff;
43917836SJohn.Forte@Sun.COM 	p[6] = (company_id >> 4) & 0xff;
43927836SJohn.Forte@Sun.COM 	p[7] = (company_id << 4) & 0xf0;
43937836SJohn.Forte@Sun.COM 	if (!localetheraddr((struct ether_addr *)NULL, &mac)) {
43948662SJordan.Vaughan@Sun.com 		int hid = BE_32((int)zone_get_hostid(NULL));
43957836SJohn.Forte@Sun.COM 		e[0] = (hid >> 24) & 0xff;
43967836SJohn.Forte@Sun.COM 		e[1] = (hid >> 16) & 0xff;
43977836SJohn.Forte@Sun.COM 		e[2] = (hid >> 8) & 0xff;
43987836SJohn.Forte@Sun.COM 		e[3] = hid & 0xff;
43997836SJohn.Forte@Sun.COM 		e[4] = e[5] = 0;
44007836SJohn.Forte@Sun.COM 	}
44017836SJohn.Forte@Sun.COM 	bcopy(e, p+8, 6);
44027836SJohn.Forte@Sun.COM 	uniqtime32(&timestamp32);
44037836SJohn.Forte@Sun.COM 	*t = BE_32(*t);
44047836SJohn.Forte@Sun.COM 	bcopy(t, p+14, 4);
44057836SJohn.Forte@Sun.COM 	p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
44067836SJohn.Forte@Sun.COM 	p[19] = stmf_lu_id_gen_number & 0xff;
44077836SJohn.Forte@Sun.COM 
44087836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
44097836SJohn.Forte@Sun.COM }
44107836SJohn.Forte@Sun.COM 
44117836SJohn.Forte@Sun.COM /*
44127836SJohn.Forte@Sun.COM  * saa is sense key, ASC, ASCQ
44137836SJohn.Forte@Sun.COM  */
44147836SJohn.Forte@Sun.COM void
44157836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa)
44167836SJohn.Forte@Sun.COM {
44177836SJohn.Forte@Sun.COM 	uint8_t sd[18];
44187836SJohn.Forte@Sun.COM 	task->task_scsi_status = st;
44197836SJohn.Forte@Sun.COM 	if (st == 2) {
44207836SJohn.Forte@Sun.COM 		bzero(sd, 18);
44217836SJohn.Forte@Sun.COM 		sd[0] = 0x70;
44227836SJohn.Forte@Sun.COM 		sd[2] = (saa >> 16) & 0xf;
44237836SJohn.Forte@Sun.COM 		sd[7] = 10;
44247836SJohn.Forte@Sun.COM 		sd[12] = (saa >> 8) & 0xff;
44257836SJohn.Forte@Sun.COM 		sd[13] = saa & 0xff;
44267836SJohn.Forte@Sun.COM 		task->task_sense_data = sd;
44277836SJohn.Forte@Sun.COM 		task->task_sense_length = 18;
44287836SJohn.Forte@Sun.COM 	} else {
44297836SJohn.Forte@Sun.COM 		task->task_sense_data = NULL;
44307836SJohn.Forte@Sun.COM 		task->task_sense_length = 0;
44317836SJohn.Forte@Sun.COM 	}
44327836SJohn.Forte@Sun.COM 	(void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
44337836SJohn.Forte@Sun.COM }
44347836SJohn.Forte@Sun.COM 
44357836SJohn.Forte@Sun.COM uint32_t
44367836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page,
44377836SJohn.Forte@Sun.COM     uint32_t page_len, uint8_t byte0, uint32_t vpd_mask)
44387836SJohn.Forte@Sun.COM {
44397836SJohn.Forte@Sun.COM 	uint8_t		*p = NULL;
44407836SJohn.Forte@Sun.COM 	uint8_t		small_buf[32];
44417836SJohn.Forte@Sun.COM 	uint32_t	sz = 0;
44427836SJohn.Forte@Sun.COM 	uint32_t	n = 4;
44437836SJohn.Forte@Sun.COM 	uint32_t	m = 0;
44447836SJohn.Forte@Sun.COM 	uint32_t	last_bit = 0;
44457836SJohn.Forte@Sun.COM 
44467836SJohn.Forte@Sun.COM 	if (page_len < 4)
44477836SJohn.Forte@Sun.COM 		return (0);
44487836SJohn.Forte@Sun.COM 	if (page_len > 65535)
44497836SJohn.Forte@Sun.COM 		page_len = 65535;
44507836SJohn.Forte@Sun.COM 
44517836SJohn.Forte@Sun.COM 	page[0] = byte0;
44527836SJohn.Forte@Sun.COM 	page[1] = 0x83;
44537836SJohn.Forte@Sun.COM 
44547836SJohn.Forte@Sun.COM 	/* CONSTCOND */
44557836SJohn.Forte@Sun.COM 	while (1) {
44567836SJohn.Forte@Sun.COM 		m += sz;
44577836SJohn.Forte@Sun.COM 		if (sz && (page_len > n)) {
44587836SJohn.Forte@Sun.COM 			uint32_t copysz;
44597836SJohn.Forte@Sun.COM 			copysz = page_len > (n + sz) ? sz : page_len - n;
44607836SJohn.Forte@Sun.COM 			bcopy(p, page + n, copysz);
44617836SJohn.Forte@Sun.COM 			n += copysz;
44627836SJohn.Forte@Sun.COM 		}
44637836SJohn.Forte@Sun.COM 		vpd_mask &= ~last_bit;
44647836SJohn.Forte@Sun.COM 		if (vpd_mask == 0)
44657836SJohn.Forte@Sun.COM 			break;
44667836SJohn.Forte@Sun.COM 
44677836SJohn.Forte@Sun.COM 		if (vpd_mask & STMF_VPD_LU_ID) {
44687836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_LU_ID;
44697836SJohn.Forte@Sun.COM 			sz = task->task_lu->lu_id->ident_length + 4;
44707836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lu->lu_id;
44717836SJohn.Forte@Sun.COM 			continue;
44727836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TARGET_ID) {
44737836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TARGET_ID;
44747836SJohn.Forte@Sun.COM 			sz = task->task_lport->lport_id->ident_length + 4;
44757836SJohn.Forte@Sun.COM 			p = (uint8_t *)task->task_lport->lport_id;
44767836SJohn.Forte@Sun.COM 			continue;
44777836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_TP_GROUP) {
44787836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_TP_GROUP;
44797836SJohn.Forte@Sun.COM 			p = small_buf;
44807836SJohn.Forte@Sun.COM 			bzero(p, 8);
44817836SJohn.Forte@Sun.COM 			p[0] = 1;
44827836SJohn.Forte@Sun.COM 			p[1] = 0x15;
44837836SJohn.Forte@Sun.COM 			p[3] = 4;
44847836SJohn.Forte@Sun.COM 			/* Group ID is always 0 */
44857836SJohn.Forte@Sun.COM 			sz = 8;
44867836SJohn.Forte@Sun.COM 			continue;
44877836SJohn.Forte@Sun.COM 		} else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) {
44887836SJohn.Forte@Sun.COM 			stmf_i_local_port_t *ilport;
44897836SJohn.Forte@Sun.COM 
44907836SJohn.Forte@Sun.COM 			last_bit = STMF_VPD_RELATIVE_TP_ID;
44917836SJohn.Forte@Sun.COM 			p = small_buf;
44927836SJohn.Forte@Sun.COM 			bzero(p, 8);
44937836SJohn.Forte@Sun.COM 			p[0] = 1;
44947836SJohn.Forte@Sun.COM 			p[1] = 0x14;
44957836SJohn.Forte@Sun.COM 			p[3] = 4;
44967836SJohn.Forte@Sun.COM 			ilport = (stmf_i_local_port_t *)
44978662SJordan.Vaughan@Sun.com 			    task->task_lport->lport_stmf_private;
44987836SJohn.Forte@Sun.COM 			p[6] = (ilport->ilport_rtpid >> 8) & 0xff;
44997836SJohn.Forte@Sun.COM 			p[7] = ilport->ilport_rtpid & 0xff;
45007836SJohn.Forte@Sun.COM 			sz = 8;
45017836SJohn.Forte@Sun.COM 			continue;
45027836SJohn.Forte@Sun.COM 		} else {
45037836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "Invalid vpd_mask");
45047836SJohn.Forte@Sun.COM 			break;
45057836SJohn.Forte@Sun.COM 		}
45067836SJohn.Forte@Sun.COM 	}
45077836SJohn.Forte@Sun.COM 
45087836SJohn.Forte@Sun.COM 	page[2] = (m >> 8) & 0xff;
45097836SJohn.Forte@Sun.COM 	page[3] = m & 0xff;
45107836SJohn.Forte@Sun.COM 
45117836SJohn.Forte@Sun.COM 	return (n);
45127836SJohn.Forte@Sun.COM }
45137836SJohn.Forte@Sun.COM 
45147836SJohn.Forte@Sun.COM void
45157836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf)
45167836SJohn.Forte@Sun.COM {
45177836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
45188662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
45197836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
45207836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
45217836SJohn.Forte@Sun.COM 
45227836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING;
45237836SJohn.Forte@Sun.COM 	task->task_cmd_xfer_length =
45247836SJohn.Forte@Sun.COM 	    ((((uint32_t)task->task_cdb[6]) << 24) |
45257836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[7]) << 16) |
45267836SJohn.Forte@Sun.COM 	    (((uint32_t)task->task_cdb[8]) << 8) |
45277836SJohn.Forte@Sun.COM 	    ((uint32_t)task->task_cdb[9]));
45287836SJohn.Forte@Sun.COM 
45297836SJohn.Forte@Sun.COM 	if (task->task_additional_flags &
45307836SJohn.Forte@Sun.COM 	    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
45317836SJohn.Forte@Sun.COM 		task->task_expected_xfer_length =
45327836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length;
45337836SJohn.Forte@Sun.COM 	}
45347836SJohn.Forte@Sun.COM 
45357836SJohn.Forte@Sun.COM 	if (task->task_cmd_xfer_length < 16) {
45367836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
45378662SJordan.Vaughan@Sun.com 		    STMF_SAA_INVALID_FIELD_IN_CDB);
45387836SJohn.Forte@Sun.COM 		return;
45397836SJohn.Forte@Sun.COM 	}
45407836SJohn.Forte@Sun.COM 
45417836SJohn.Forte@Sun.COM 	sz = min(task->task_expected_xfer_length,
45427836SJohn.Forte@Sun.COM 	    task->task_cmd_xfer_length);
45437836SJohn.Forte@Sun.COM 
45447836SJohn.Forte@Sun.COM 	xd = stmf_prepare_tpgs_data();
45457836SJohn.Forte@Sun.COM 
45467836SJohn.Forte@Sun.COM 	if (xd == NULL) {
45477836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
45487836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
45497836SJohn.Forte@Sun.COM 		return;
45507836SJohn.Forte@Sun.COM 	}
45517836SJohn.Forte@Sun.COM 
45527836SJohn.Forte@Sun.COM 	sz = min(sz, xd->size_left);
45537836SJohn.Forte@Sun.COM 	xd->size_left = sz;
45547836SJohn.Forte@Sun.COM 	minsz = min(512, sz);
45557836SJohn.Forte@Sun.COM 
45567836SJohn.Forte@Sun.COM 	if (dbuf == NULL)
45577836SJohn.Forte@Sun.COM 		dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
45587836SJohn.Forte@Sun.COM 	if (dbuf == NULL) {
45597836SJohn.Forte@Sun.COM 		kmem_free(xd, xd->alloc_size);
45607836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
45617836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
45627836SJohn.Forte@Sun.COM 		return;
45637836SJohn.Forte@Sun.COM 	}
45647836SJohn.Forte@Sun.COM 	dbuf->db_lu_private = xd;
45657836SJohn.Forte@Sun.COM 	stmf_xd_to_dbuf(dbuf);
45667836SJohn.Forte@Sun.COM 
45677836SJohn.Forte@Sun.COM 	dbuf->db_flags = DB_DIRECTION_TO_RPORT;
45687836SJohn.Forte@Sun.COM 	(void) stmf_xfer_data(task, dbuf, 0);
45697836SJohn.Forte@Sun.COM 
45707836SJohn.Forte@Sun.COM }
45717836SJohn.Forte@Sun.COM 
45727836SJohn.Forte@Sun.COM void
45737836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task)
45747836SJohn.Forte@Sun.COM {
45757836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
45767836SJohn.Forte@Sun.COM 	/*
45777836SJohn.Forte@Sun.COM 	 * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET
45787836SJohn.Forte@Sun.COM 	 * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state
45797836SJohn.Forte@Sun.COM 	 * in these cases. This needs to be changed to abort only the required
45807836SJohn.Forte@Sun.COM 	 * set.
45817836SJohn.Forte@Sun.COM 	 */
45827836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
45837836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
45847836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
45857836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
45867836SJohn.Forte@Sun.COM 		stmf_handle_lun_reset(task);
45877836SJohn.Forte@Sun.COM 		return;
45887836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
45897836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
45907836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
45917836SJohn.Forte@Sun.COM 		stmf_handle_target_reset(task);
45927836SJohn.Forte@Sun.COM 		return;
45937836SJohn.Forte@Sun.COM 	default:
45947836SJohn.Forte@Sun.COM 		/* We dont support this task mgmt function */
45957836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
45967836SJohn.Forte@Sun.COM 		    STMF_SAA_INVALID_FIELD_IN_CMD_IU);
45977836SJohn.Forte@Sun.COM 		return;
45987836SJohn.Forte@Sun.COM 	}
45997836SJohn.Forte@Sun.COM }
46007836SJohn.Forte@Sun.COM 
46017836SJohn.Forte@Sun.COM void
46027836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task)
46037836SJohn.Forte@Sun.COM {
46047836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
46057836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
46067836SJohn.Forte@Sun.COM 
46077836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
46087836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
46097836SJohn.Forte@Sun.COM 
46107836SJohn.Forte@Sun.COM 	/*
46117836SJohn.Forte@Sun.COM 	 * To sync with target reset, grab this lock. The LU is not going
46127836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
46137836SJohn.Forte@Sun.COM 	 */
46147836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
46157836SJohn.Forte@Sun.COM 
46167836SJohn.Forte@Sun.COM 	if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
46177836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
46187836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
46198662SJordan.Vaughan@Sun.com 		    STMF_SAA_OPERATION_IN_PROGRESS);
46207836SJohn.Forte@Sun.COM 		return;
46217836SJohn.Forte@Sun.COM 	}
46227836SJohn.Forte@Sun.COM 	atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
46237836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
46247836SJohn.Forte@Sun.COM 
46257836SJohn.Forte@Sun.COM 	/*
46267836SJohn.Forte@Sun.COM 	 * Mark this task as the one causing LU reset so that we know who
46277836SJohn.Forte@Sun.COM 	 * was responsible for setting the ILU_RESET_ACTIVE. In case this
46287836SJohn.Forte@Sun.COM 	 * task itself gets aborted, we will clear ILU_RESET_ACTIVE.
46297836SJohn.Forte@Sun.COM 	 */
46307836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET;
46317836SJohn.Forte@Sun.COM 
46327836SJohn.Forte@Sun.COM 	/* Initiatiate abort on all commands on this LU except this one */
46337836SJohn.Forte@Sun.COM 	stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu);
46347836SJohn.Forte@Sun.COM 
46357836SJohn.Forte@Sun.COM 	/* Start polling on this task */
46367836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
46377836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
46387836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
46398662SJordan.Vaughan@Sun.com 		    NULL);
46407836SJohn.Forte@Sun.COM 		return;
46417836SJohn.Forte@Sun.COM 	}
46427836SJohn.Forte@Sun.COM }
46437836SJohn.Forte@Sun.COM 
46447836SJohn.Forte@Sun.COM void
46457836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task)
46467836SJohn.Forte@Sun.COM {
46477836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
46487836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
46497836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
46507836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
46517836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
46527836SJohn.Forte@Sun.COM 	int i, lf;
46537836SJohn.Forte@Sun.COM 
46547836SJohn.Forte@Sun.COM 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
46557836SJohn.Forte@Sun.COM 	iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private;
46567836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
46577836SJohn.Forte@Sun.COM 
46587836SJohn.Forte@Sun.COM 	/*
46597836SJohn.Forte@Sun.COM 	 * To sync with LUN reset, grab this lock. The session is not going
46607836SJohn.Forte@Sun.COM 	 * anywhere as there is atleast one task pending (this task).
46617836SJohn.Forte@Sun.COM 	 */
46627836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
46637979SSumit.Gupta@Sun.COM 
46647979SSumit.Gupta@Sun.COM 	/* Grab the session lock as a writer to prevent any changes in it */
46657979SSumit.Gupta@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
46667979SSumit.Gupta@Sun.COM 
46677836SJohn.Forte@Sun.COM 	if (iss->iss_flags & ISS_RESET_ACTIVE) {
46687979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
46697836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
46707836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_CHECK,
46718662SJordan.Vaughan@Sun.com 		    STMF_SAA_OPERATION_IN_PROGRESS);
46727836SJohn.Forte@Sun.COM 		return;
46737836SJohn.Forte@Sun.COM 	}
46747836SJohn.Forte@Sun.COM 	atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE);
46757836SJohn.Forte@Sun.COM 
46767836SJohn.Forte@Sun.COM 	/*
46777836SJohn.Forte@Sun.COM 	 * Now go through each LUN in this session and make sure all of them
46787836SJohn.Forte@Sun.COM 	 * can be reset.
46797836SJohn.Forte@Sun.COM 	 */
46807836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
46817836SJohn.Forte@Sun.COM 	for (i = 0, lf = 0; i < lm->lm_nentries; i++) {
46827836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
46837836SJohn.Forte@Sun.COM 			continue;
46847836SJohn.Forte@Sun.COM 		lf++;
46857836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
46867836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
46877836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
46887836SJohn.Forte@Sun.COM 			atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
46897979SSumit.Gupta@Sun.COM 			rw_exit(iss->iss_lockp);
46907836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
46917836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
46928662SJordan.Vaughan@Sun.com 			    STMF_SAA_OPERATION_IN_PROGRESS);
46937836SJohn.Forte@Sun.COM 			return;
46947836SJohn.Forte@Sun.COM 		}
46957836SJohn.Forte@Sun.COM 	}
46967836SJohn.Forte@Sun.COM 	if (lf == 0) {
46977836SJohn.Forte@Sun.COM 		/* No luns in this session */
46987836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
46997979SSumit.Gupta@Sun.COM 		rw_exit(iss->iss_lockp);
47007836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
47017836SJohn.Forte@Sun.COM 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
47027836SJohn.Forte@Sun.COM 		return;
47037836SJohn.Forte@Sun.COM 	}
47047836SJohn.Forte@Sun.COM 
47057836SJohn.Forte@Sun.COM 	/* ok, start the damage */
47067836SJohn.Forte@Sun.COM 	itask->itask_flags |= ITASK_DEFAULT_HANDLING |
47078662SJordan.Vaughan@Sun.com 	    ITASK_CAUSING_TARGET_RESET;
47087836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
47097836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
47107836SJohn.Forte@Sun.COM 			continue;
47117836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
47127836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
47137836SJohn.Forte@Sun.COM 		atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
47147836SJohn.Forte@Sun.COM 	}
47157979SSumit.Gupta@Sun.COM 	rw_exit(iss->iss_lockp);
47167836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
47177836SJohn.Forte@Sun.COM 
47187836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
47197836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
47207836SJohn.Forte@Sun.COM 			continue;
47217836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
47227836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
47238662SJordan.Vaughan@Sun.com 		    lm_ent->ent_lu);
47247836SJohn.Forte@Sun.COM 	}
47257836SJohn.Forte@Sun.COM 
47267836SJohn.Forte@Sun.COM 	/* Start polling on this task */
47277836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
47287836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
47297836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
47308662SJordan.Vaughan@Sun.com 		    NULL);
47317836SJohn.Forte@Sun.COM 		return;
47327836SJohn.Forte@Sun.COM 	}
47337836SJohn.Forte@Sun.COM }
47347836SJohn.Forte@Sun.COM 
47357836SJohn.Forte@Sun.COM int
47367836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask)
47377836SJohn.Forte@Sun.COM {
47387836SJohn.Forte@Sun.COM 	scsi_task_t *task = itask->itask_task;
47397836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
47407836SJohn.Forte@Sun.COM 	    task->task_session->ss_stmf_private;
47417836SJohn.Forte@Sun.COM 
47427836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_WRITER);
47437836SJohn.Forte@Sun.COM 	if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) ||
47447836SJohn.Forte@Sun.COM 	    (task->task_cdb[0] == SCMD_INQUIRY)) {
47457836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
47467836SJohn.Forte@Sun.COM 		return (0);
47477836SJohn.Forte@Sun.COM 	}
47487836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags,
47498662SJordan.Vaughan@Sun.com 	    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
47507836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
47517836SJohn.Forte@Sun.COM 
47527836SJohn.Forte@Sun.COM 	if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
47537836SJohn.Forte@Sun.COM 		return (0);
47547836SJohn.Forte@Sun.COM 	}
47557836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK,
47567836SJohn.Forte@Sun.COM 	    STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED);
47577836SJohn.Forte@Sun.COM 	return (1);
47587836SJohn.Forte@Sun.COM }
47597836SJohn.Forte@Sun.COM 
47607836SJohn.Forte@Sun.COM void
47617836SJohn.Forte@Sun.COM stmf_worker_init()
47627836SJohn.Forte@Sun.COM {
47637836SJohn.Forte@Sun.COM 	uint32_t i;
47647836SJohn.Forte@Sun.COM 
47657836SJohn.Forte@Sun.COM 	/* Make local copy of global tunables */
47667836SJohn.Forte@Sun.COM 	stmf_i_max_nworkers = stmf_max_nworkers;
47677836SJohn.Forte@Sun.COM 	stmf_i_min_nworkers = stmf_min_nworkers;
47687836SJohn.Forte@Sun.COM 
47697836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers == NULL);
47707836SJohn.Forte@Sun.COM 	if (stmf_i_min_nworkers < 4) {
47717836SJohn.Forte@Sun.COM 		stmf_i_min_nworkers = 4;
47727836SJohn.Forte@Sun.COM 	}
47737836SJohn.Forte@Sun.COM 	if (stmf_i_max_nworkers < stmf_i_min_nworkers) {
47747836SJohn.Forte@Sun.COM 		stmf_i_max_nworkers = stmf_i_min_nworkers;
47757836SJohn.Forte@Sun.COM 	}
47767836SJohn.Forte@Sun.COM 	stmf_workers = (stmf_worker_t *)kmem_zalloc(
47777836SJohn.Forte@Sun.COM 	    sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP);
47787836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
47797836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
47807836SJohn.Forte@Sun.COM 		mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
47817836SJohn.Forte@Sun.COM 		cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
47827836SJohn.Forte@Sun.COM 	}
47837836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
47847836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_ENABLED;
47857836SJohn.Forte@Sun.COM 
47867836SJohn.Forte@Sun.COM 	/* Workers will be started by stmf_worker_mgmt() */
47877836SJohn.Forte@Sun.COM 
47887836SJohn.Forte@Sun.COM 	/* Lets wait for atleast one worker to start */
47897836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur == 0)
47907836SJohn.Forte@Sun.COM 		delay(drv_usectohz(20 * 1000));
47917836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000);
47927836SJohn.Forte@Sun.COM }
47937836SJohn.Forte@Sun.COM 
47947836SJohn.Forte@Sun.COM stmf_status_t
47957836SJohn.Forte@Sun.COM stmf_worker_fini()
47967836SJohn.Forte@Sun.COM {
47977836SJohn.Forte@Sun.COM 	int i;
47987836SJohn.Forte@Sun.COM 	clock_t sb;
47997836SJohn.Forte@Sun.COM 
48007836SJohn.Forte@Sun.COM 	if (stmf_workers_state == STMF_WORKERS_DISABLED)
48017836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
48027836SJohn.Forte@Sun.COM 	ASSERT(stmf_workers);
48037836SJohn.Forte@Sun.COM 	stmf_workers_state = STMF_WORKERS_DISABLED;
48047836SJohn.Forte@Sun.COM 	stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
48057836SJohn.Forte@Sun.COM 	cv_signal(&stmf_state.stmf_cv);
48067836SJohn.Forte@Sun.COM 
48077836SJohn.Forte@Sun.COM 	sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000);
48087836SJohn.Forte@Sun.COM 	/* Wait for all the threads to die */
48097836SJohn.Forte@Sun.COM 	while (stmf_nworkers_cur != 0) {
48107836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > sb) {
48117836SJohn.Forte@Sun.COM 			stmf_workers_state = STMF_WORKERS_ENABLED;
48127836SJohn.Forte@Sun.COM 			return (STMF_BUSY);
48137836SJohn.Forte@Sun.COM 		}
48147836SJohn.Forte@Sun.COM 		delay(drv_usectohz(100 * 1000));
48157836SJohn.Forte@Sun.COM 	}
48167836SJohn.Forte@Sun.COM 	for (i = 0; i < stmf_i_max_nworkers; i++) {
48177836SJohn.Forte@Sun.COM 		stmf_worker_t *w = &stmf_workers[i];
48187836SJohn.Forte@Sun.COM 		mutex_destroy(&w->worker_lock);
48197836SJohn.Forte@Sun.COM 		cv_destroy(&w->worker_cv);
48207836SJohn.Forte@Sun.COM 	}
48217836SJohn.Forte@Sun.COM 	kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers);
48227836SJohn.Forte@Sun.COM 	stmf_workers = NULL;
48237836SJohn.Forte@Sun.COM 
48247836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
48257836SJohn.Forte@Sun.COM }
48267836SJohn.Forte@Sun.COM 
48277836SJohn.Forte@Sun.COM void
48287836SJohn.Forte@Sun.COM stmf_worker_task(void *arg)
48297836SJohn.Forte@Sun.COM {
48307836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
48317836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
48327836SJohn.Forte@Sun.COM 	scsi_task_t *task;
48337836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask;
48347836SJohn.Forte@Sun.COM 	stmf_data_buf_t *dbuf;
48357836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
48367836SJohn.Forte@Sun.COM 	clock_t wait_timer = 0;
48377836SJohn.Forte@Sun.COM 	clock_t wait_ticks;
48387836SJohn.Forte@Sun.COM 	uint32_t old, new;
48397836SJohn.Forte@Sun.COM 	uint8_t curcmd;
48407836SJohn.Forte@Sun.COM 	uint8_t abort_free;
48417836SJohn.Forte@Sun.COM 	uint8_t wait_queue;
48427836SJohn.Forte@Sun.COM 	uint8_t dec_qdepth;
48437836SJohn.Forte@Sun.COM 
48447836SJohn.Forte@Sun.COM 	w = (stmf_worker_t *)arg;
48457836SJohn.Forte@Sun.COM 	wait_ticks = drv_usectohz(10000);
48467836SJohn.Forte@Sun.COM 
48477836SJohn.Forte@Sun.COM 	mutex_enter(&w->worker_lock);
48487836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE;
48497836SJohn.Forte@Sun.COM stmf_worker_loop:;
48507836SJohn.Forte@Sun.COM 	if ((w->worker_ref_count == 0) &&
48517836SJohn.Forte@Sun.COM 	    (w->worker_flags & STMF_WORKER_TERMINATE)) {
48527836SJohn.Forte@Sun.COM 		w->worker_flags &= ~(STMF_WORKER_STARTED |
48537836SJohn.Forte@Sun.COM 		    STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE);
48547836SJohn.Forte@Sun.COM 		w->worker_tid = NULL;
48557836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
48567836SJohn.Forte@Sun.COM 		thread_exit();
48577836SJohn.Forte@Sun.COM 	}
48587836SJohn.Forte@Sun.COM 	/* CONSTCOND */
48597836SJohn.Forte@Sun.COM 	while (1) {
48607836SJohn.Forte@Sun.COM 		dec_qdepth = 0;
48617836SJohn.Forte@Sun.COM 		if (wait_timer && (ddi_get_lbolt() >= wait_timer)) {
48627836SJohn.Forte@Sun.COM 			wait_timer = 0;
48637979SSumit.Gupta@Sun.COM 			if (w->worker_wait_head) {
48647979SSumit.Gupta@Sun.COM 				ASSERT(w->worker_wait_tail);
48657979SSumit.Gupta@Sun.COM 				if (w->worker_task_head == NULL)
48667979SSumit.Gupta@Sun.COM 					w->worker_task_head =
48677979SSumit.Gupta@Sun.COM 					    w->worker_wait_head;
48687979SSumit.Gupta@Sun.COM 				else
48697979SSumit.Gupta@Sun.COM 					w->worker_task_tail->itask_worker_next =
48708662SJordan.Vaughan@Sun.com 					    w->worker_wait_head;
48717979SSumit.Gupta@Sun.COM 				w->worker_task_tail = w->worker_wait_tail;
48727979SSumit.Gupta@Sun.COM 				w->worker_wait_head = w->worker_wait_tail =
48737979SSumit.Gupta@Sun.COM 				    NULL;
48747979SSumit.Gupta@Sun.COM 			}
48757836SJohn.Forte@Sun.COM 		}
48767836SJohn.Forte@Sun.COM 		if ((itask = w->worker_task_head) == NULL) {
48777836SJohn.Forte@Sun.COM 			break;
48787836SJohn.Forte@Sun.COM 		}
48797836SJohn.Forte@Sun.COM 		task = itask->itask_task;
48807836SJohn.Forte@Sun.COM 		w->worker_task_head = itask->itask_worker_next;
48817836SJohn.Forte@Sun.COM 		if (w->worker_task_head == NULL)
48827836SJohn.Forte@Sun.COM 			w->worker_task_tail = NULL;
48837836SJohn.Forte@Sun.COM 
48847836SJohn.Forte@Sun.COM 		wait_queue = 0;
48857836SJohn.Forte@Sun.COM 		abort_free = 0;
48867836SJohn.Forte@Sun.COM 		if (itask->itask_ncmds > 0) {
48877836SJohn.Forte@Sun.COM 			curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1];
48887836SJohn.Forte@Sun.COM 		} else {
48897836SJohn.Forte@Sun.COM 			ASSERT(itask->itask_flags & ITASK_BEING_ABORTED);
48907836SJohn.Forte@Sun.COM 		}
48917836SJohn.Forte@Sun.COM 		do {
48927836SJohn.Forte@Sun.COM 			old = itask->itask_flags;
48937836SJohn.Forte@Sun.COM 			if (old & ITASK_BEING_ABORTED) {
48947836SJohn.Forte@Sun.COM 				itask->itask_ncmds = 1;
48957836SJohn.Forte@Sun.COM 				curcmd = itask->itask_cmd_stack[0] =
48967836SJohn.Forte@Sun.COM 				    ITASK_CMD_ABORT;
48977836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
48987836SJohn.Forte@Sun.COM 			} else if ((curcmd & ITASK_CMD_MASK) ==
48997836SJohn.Forte@Sun.COM 			    ITASK_CMD_NEW_TASK) {
49007836SJohn.Forte@Sun.COM 				new = old | ITASK_KNOWN_TO_LU;
49017836SJohn.Forte@Sun.COM 			} else {
49027836SJohn.Forte@Sun.COM 				goto out_itask_flag_loop;
49037836SJohn.Forte@Sun.COM 			}
49047836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&itask->itask_flags, old, new) != old);
49057836SJohn.Forte@Sun.COM 
49067836SJohn.Forte@Sun.COM out_itask_flag_loop:
49077836SJohn.Forte@Sun.COM 
49087836SJohn.Forte@Sun.COM 		/*
49097836SJohn.Forte@Sun.COM 		 * Decide if this task needs to go to a queue and/or if
49107836SJohn.Forte@Sun.COM 		 * we can decrement the itask_cmd_stack.
49117836SJohn.Forte@Sun.COM 		 */
49127836SJohn.Forte@Sun.COM 		if (curcmd == ITASK_CMD_ABORT) {
49137836SJohn.Forte@Sun.COM 			if (itask->itask_flags & (ITASK_KNOWN_TO_LU |
49147836SJohn.Forte@Sun.COM 			    ITASK_KNOWN_TO_TGT_PORT)) {
49157836SJohn.Forte@Sun.COM 				wait_queue = 1;
49167836SJohn.Forte@Sun.COM 			} else {
49177836SJohn.Forte@Sun.COM 				abort_free = 1;
49187836SJohn.Forte@Sun.COM 			}
49197836SJohn.Forte@Sun.COM 		} else if ((curcmd & ITASK_CMD_POLL) &&
49207836SJohn.Forte@Sun.COM 		    (itask->itask_poll_timeout > ddi_get_lbolt())) {
49217836SJohn.Forte@Sun.COM 			wait_queue = 1;
49227836SJohn.Forte@Sun.COM 		}
49237836SJohn.Forte@Sun.COM 
49247836SJohn.Forte@Sun.COM 		if (wait_queue) {
49257836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
49267836SJohn.Forte@Sun.COM 			if (w->worker_wait_tail) {
49277836SJohn.Forte@Sun.COM 				w->worker_wait_tail->itask_worker_next = itask;
49287836SJohn.Forte@Sun.COM 			} else {
49297836SJohn.Forte@Sun.COM 				w->worker_wait_head = itask;
49307836SJohn.Forte@Sun.COM 			}
49317836SJohn.Forte@Sun.COM 			w->worker_wait_tail = itask;
49327836SJohn.Forte@Sun.COM 			if (wait_timer == 0) {
49337836SJohn.Forte@Sun.COM 				wait_timer = ddi_get_lbolt() + wait_ticks;
49347836SJohn.Forte@Sun.COM 			}
49357836SJohn.Forte@Sun.COM 		} else if ((--(itask->itask_ncmds)) != 0) {
49367836SJohn.Forte@Sun.COM 			itask->itask_worker_next = NULL;
49377836SJohn.Forte@Sun.COM 			if (w->worker_task_tail) {
49387836SJohn.Forte@Sun.COM 				w->worker_task_tail->itask_worker_next = itask;
49397836SJohn.Forte@Sun.COM 			} else {
49407836SJohn.Forte@Sun.COM 				w->worker_task_head = itask;
49417836SJohn.Forte@Sun.COM 			}
49427836SJohn.Forte@Sun.COM 			w->worker_task_tail = itask;
49437836SJohn.Forte@Sun.COM 		} else {
49447836SJohn.Forte@Sun.COM 			atomic_and_32(&itask->itask_flags,
49457836SJohn.Forte@Sun.COM 			    ~ITASK_IN_WORKER_QUEUE);
49467836SJohn.Forte@Sun.COM 			/*
49477836SJohn.Forte@Sun.COM 			 * This is where the queue depth should go down by
49487836SJohn.Forte@Sun.COM 			 * one but we delay that on purpose to account for
49497836SJohn.Forte@Sun.COM 			 * the call into the provider. The actual decrement
49507836SJohn.Forte@Sun.COM 			 * happens after the worker has done its job.
49517836SJohn.Forte@Sun.COM 			 */
49527836SJohn.Forte@Sun.COM 			dec_qdepth = 1;
49537836SJohn.Forte@Sun.COM 		}
49547836SJohn.Forte@Sun.COM 
49557836SJohn.Forte@Sun.COM 		/* We made it here means we are going to call LU */
49567836SJohn.Forte@Sun.COM 		if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0)
49577836SJohn.Forte@Sun.COM 			lu = task->task_lu;
49587836SJohn.Forte@Sun.COM 		else
49597836SJohn.Forte@Sun.COM 			lu = dlun0;
49607836SJohn.Forte@Sun.COM 		dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)];
49617836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
49627836SJohn.Forte@Sun.COM 		curcmd &= ITASK_CMD_MASK;
49637836SJohn.Forte@Sun.COM 		switch (curcmd) {
49647836SJohn.Forte@Sun.COM 		case ITASK_CMD_NEW_TASK:
49657836SJohn.Forte@Sun.COM 			iss = (stmf_i_scsi_session_t *)
49667836SJohn.Forte@Sun.COM 			    task->task_session->ss_stmf_private;
49679435STim.Szeto@Sun.COM 			stmf_update_kstat_lu_q(task, kstat_waitq_to_runq);
49689435STim.Szeto@Sun.COM 			stmf_update_kstat_lport_q(task, kstat_waitq_to_runq);
49697836SJohn.Forte@Sun.COM 			if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) {
49707836SJohn.Forte@Sun.COM 				if (stmf_handle_cmd_during_ic(itask))
49717836SJohn.Forte@Sun.COM 					break;
49727836SJohn.Forte@Sun.COM 			}
49737836SJohn.Forte@Sun.COM #ifdef	DEBUG
49747836SJohn.Forte@Sun.COM 			if (stmf_drop_task_counter > 0) {
49757836SJohn.Forte@Sun.COM 				if (atomic_add_32_nv(
49767836SJohn.Forte@Sun.COM 				    (uint32_t *)&stmf_drop_task_counter,
49777836SJohn.Forte@Sun.COM 				    -1) == 1) {
49787836SJohn.Forte@Sun.COM 					break;
49797836SJohn.Forte@Sun.COM 				}
49807836SJohn.Forte@Sun.COM 			}
49817836SJohn.Forte@Sun.COM #endif
49828859STim.Szeto@Sun.COM 			DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task);
49837836SJohn.Forte@Sun.COM 			lu->lu_new_task(task, dbuf);
49847836SJohn.Forte@Sun.COM 			break;
49857836SJohn.Forte@Sun.COM 		case ITASK_CMD_DATA_XFER_DONE:
49867836SJohn.Forte@Sun.COM 			lu->lu_dbuf_xfer_done(task, dbuf);
49877836SJohn.Forte@Sun.COM 			break;
49887836SJohn.Forte@Sun.COM 		case ITASK_CMD_STATUS_DONE:
49897836SJohn.Forte@Sun.COM 			lu->lu_send_status_done(task);
49907836SJohn.Forte@Sun.COM 			break;
49917836SJohn.Forte@Sun.COM 		case ITASK_CMD_ABORT:
49927836SJohn.Forte@Sun.COM 			if (abort_free) {
49937836SJohn.Forte@Sun.COM 				stmf_task_free(task);
49947836SJohn.Forte@Sun.COM 			} else {
49957836SJohn.Forte@Sun.COM 				stmf_do_task_abort(task);
49967836SJohn.Forte@Sun.COM 			}
49977836SJohn.Forte@Sun.COM 			break;
49987836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LU:
49997836SJohn.Forte@Sun.COM 			if (!wait_queue) {
50007836SJohn.Forte@Sun.COM 				lu->lu_task_poll(task);
50017836SJohn.Forte@Sun.COM 			}
50027836SJohn.Forte@Sun.COM 			break;
50037836SJohn.Forte@Sun.COM 		case ITASK_CMD_POLL_LPORT:
50047836SJohn.Forte@Sun.COM 			if (!wait_queue)
50057836SJohn.Forte@Sun.COM 				task->task_lport->lport_task_poll(task);
50067836SJohn.Forte@Sun.COM 			break;
50077836SJohn.Forte@Sun.COM 		case ITASK_CMD_SEND_STATUS:
50087836SJohn.Forte@Sun.COM 		/* case ITASK_CMD_XFER_DATA: */
50097836SJohn.Forte@Sun.COM 			break;
50107836SJohn.Forte@Sun.COM 		}
50117836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
50127836SJohn.Forte@Sun.COM 		if (dec_qdepth) {
50137836SJohn.Forte@Sun.COM 			w->worker_queue_depth--;
50147836SJohn.Forte@Sun.COM 		}
50157836SJohn.Forte@Sun.COM 	}
50167836SJohn.Forte@Sun.COM 	if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) {
50177836SJohn.Forte@Sun.COM 		if (w->worker_ref_count == 0)
50187836SJohn.Forte@Sun.COM 			goto stmf_worker_loop;
50197836SJohn.Forte@Sun.COM 		else
50207836SJohn.Forte@Sun.COM 			wait_timer = ddi_get_lbolt() + 1;
50217836SJohn.Forte@Sun.COM 	}
50227836SJohn.Forte@Sun.COM 	w->worker_flags &= ~STMF_WORKER_ACTIVE;
50237836SJohn.Forte@Sun.COM 	if (wait_timer) {
50247836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer);
50257836SJohn.Forte@Sun.COM 	} else {
50267836SJohn.Forte@Sun.COM 		cv_wait(&w->worker_cv, &w->worker_lock);
50277836SJohn.Forte@Sun.COM 	}
50287836SJohn.Forte@Sun.COM 	w->worker_flags |= STMF_WORKER_ACTIVE;
50297836SJohn.Forte@Sun.COM 	goto stmf_worker_loop;
50307836SJohn.Forte@Sun.COM }
50317836SJohn.Forte@Sun.COM 
50327836SJohn.Forte@Sun.COM void
50337836SJohn.Forte@Sun.COM stmf_worker_mgmt()
50347836SJohn.Forte@Sun.COM {
50357836SJohn.Forte@Sun.COM 	int i;
50367836SJohn.Forte@Sun.COM 	int workers_needed;
50377836SJohn.Forte@Sun.COM 	uint32_t qd;
50387836SJohn.Forte@Sun.COM 	clock_t tps, d = 0;
50397836SJohn.Forte@Sun.COM 	uint32_t cur_max_ntasks = 0;
50407836SJohn.Forte@Sun.COM 	stmf_worker_t *w;
50417836SJohn.Forte@Sun.COM 
50427836SJohn.Forte@Sun.COM 	/* Check if we are trying to increase the # of threads */
50437836SJohn.Forte@Sun.COM 	for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) {
50447836SJohn.Forte@Sun.COM 		if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) {
50457836SJohn.Forte@Sun.COM 			stmf_nworkers_cur++;
50467836SJohn.Forte@Sun.COM 			stmf_nworkers_accepting_cmds++;
50477836SJohn.Forte@Sun.COM 		} else {
50487836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
50497836SJohn.Forte@Sun.COM 			return;
50507836SJohn.Forte@Sun.COM 		}
50517836SJohn.Forte@Sun.COM 	}
50527836SJohn.Forte@Sun.COM 	/* Check if we are trying to decrease the # of workers */
50537836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
50547836SJohn.Forte@Sun.COM 		if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) {
50557836SJohn.Forte@Sun.COM 			stmf_nworkers_cur--;
50567836SJohn.Forte@Sun.COM 			/*
50577836SJohn.Forte@Sun.COM 			 * stmf_nworkers_accepting_cmds has already been
50587836SJohn.Forte@Sun.COM 			 * updated by the request to reduce the # of workers.
50597836SJohn.Forte@Sun.COM 			 */
50607836SJohn.Forte@Sun.COM 		} else {
50617836SJohn.Forte@Sun.COM 			/* Wait for transition to complete */
50627836SJohn.Forte@Sun.COM 			return;
50637836SJohn.Forte@Sun.COM 		}
50647836SJohn.Forte@Sun.COM 	}
50657836SJohn.Forte@Sun.COM 	/* Check if we are being asked to quit */
50667836SJohn.Forte@Sun.COM 	if (stmf_workers_state != STMF_WORKERS_ENABLED) {
50677836SJohn.Forte@Sun.COM 		if (stmf_nworkers_cur) {
50687836SJohn.Forte@Sun.COM 			workers_needed = 0;
50697836SJohn.Forte@Sun.COM 			goto worker_mgmt_trigger_change;
50707836SJohn.Forte@Sun.COM 		}
50717836SJohn.Forte@Sun.COM 		return;
50727836SJohn.Forte@Sun.COM 	}
50737836SJohn.Forte@Sun.COM 	/* Check if we are starting */
50747836SJohn.Forte@Sun.COM 	if (stmf_nworkers_cur < stmf_i_min_nworkers) {
50757836SJohn.Forte@Sun.COM 		workers_needed = stmf_i_min_nworkers;
50767836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
50777836SJohn.Forte@Sun.COM 	}
50787836SJohn.Forte@Sun.COM 
50797836SJohn.Forte@Sun.COM 	tps = drv_usectohz(1 * 1000 * 1000);
50807836SJohn.Forte@Sun.COM 	if ((stmf_wm_last != 0) &&
50817836SJohn.Forte@Sun.COM 	    ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) {
50827836SJohn.Forte@Sun.COM 		qd = 0;
50837836SJohn.Forte@Sun.COM 		for (i = 0; i < stmf_nworkers_accepting_cmds; i++) {
50847836SJohn.Forte@Sun.COM 			qd += stmf_workers[i].worker_max_qdepth_pu;
50857836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_qdepth_pu = 0;
50867836SJohn.Forte@Sun.COM 			if (stmf_workers[i].worker_max_sys_qdepth_pu >
50877836SJohn.Forte@Sun.COM 			    cur_max_ntasks) {
50887836SJohn.Forte@Sun.COM 				cur_max_ntasks =
50897836SJohn.Forte@Sun.COM 				    stmf_workers[i].worker_max_sys_qdepth_pu;
50907836SJohn.Forte@Sun.COM 			}
50917836SJohn.Forte@Sun.COM 			stmf_workers[i].worker_max_sys_qdepth_pu = 0;
50927836SJohn.Forte@Sun.COM 		}
50937836SJohn.Forte@Sun.COM 	}
50947836SJohn.Forte@Sun.COM 	stmf_wm_last = ddi_get_lbolt();
50957836SJohn.Forte@Sun.COM 	if (d <= tps) {
50967836SJohn.Forte@Sun.COM 		/* still ramping up */
50977836SJohn.Forte@Sun.COM 		return;
50987836SJohn.Forte@Sun.COM 	}
50997836SJohn.Forte@Sun.COM 	/* max qdepth cannot be more than max tasks */
51007836SJohn.Forte@Sun.COM 	if (qd > cur_max_ntasks)
51017836SJohn.Forte@Sun.COM 		qd = cur_max_ntasks;
51027836SJohn.Forte@Sun.COM 
51037836SJohn.Forte@Sun.COM 	/* See if we have more workers */
51047836SJohn.Forte@Sun.COM 	if (qd < stmf_nworkers_accepting_cmds) {
51057836SJohn.Forte@Sun.COM 		/*
51067836SJohn.Forte@Sun.COM 		 * Since we dont reduce the worker count right away, monitor
51077836SJohn.Forte@Sun.COM 		 * the highest load during the scale_down_delay.
51087836SJohn.Forte@Sun.COM 		 */
51097836SJohn.Forte@Sun.COM 		if (qd > stmf_worker_scale_down_qd)
51107836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = qd;
51117836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_timer == 0) {
51127836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_timer = ddi_get_lbolt() +
51137836SJohn.Forte@Sun.COM 			    drv_usectohz(stmf_worker_scale_down_delay *
51147836SJohn.Forte@Sun.COM 			    1000 * 1000);
51157836SJohn.Forte@Sun.COM 			return;
51167836SJohn.Forte@Sun.COM 		}
51177836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() < stmf_worker_scale_down_timer) {
51187836SJohn.Forte@Sun.COM 			return;
51197836SJohn.Forte@Sun.COM 		}
51207836SJohn.Forte@Sun.COM 		/* Its time to reduce the workers */
51217836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd < stmf_i_min_nworkers)
51227836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_min_nworkers;
51237836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd > stmf_i_max_nworkers)
51247836SJohn.Forte@Sun.COM 			stmf_worker_scale_down_qd = stmf_i_max_nworkers;
51257836SJohn.Forte@Sun.COM 		if (stmf_worker_scale_down_qd == stmf_nworkers_cur)
51267836SJohn.Forte@Sun.COM 			return;
51277836SJohn.Forte@Sun.COM 		workers_needed = stmf_worker_scale_down_qd;
51287836SJohn.Forte@Sun.COM 		stmf_worker_scale_down_qd = 0;
51297836SJohn.Forte@Sun.COM 		goto worker_mgmt_trigger_change;
51307836SJohn.Forte@Sun.COM 	}
51317836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_qd = 0;
51327836SJohn.Forte@Sun.COM 	stmf_worker_scale_down_timer = 0;
51337836SJohn.Forte@Sun.COM 	if (qd > stmf_i_max_nworkers)
51347836SJohn.Forte@Sun.COM 		qd = stmf_i_max_nworkers;
51357836SJohn.Forte@Sun.COM 	if (qd < stmf_i_min_nworkers)
51367836SJohn.Forte@Sun.COM 		qd = stmf_i_min_nworkers;
51377836SJohn.Forte@Sun.COM 	if (qd == stmf_nworkers_cur)
51387836SJohn.Forte@Sun.COM 		return;
51397836SJohn.Forte@Sun.COM 	workers_needed = qd;
51407836SJohn.Forte@Sun.COM 	goto worker_mgmt_trigger_change;
51417836SJohn.Forte@Sun.COM 
51427836SJohn.Forte@Sun.COM 	/* NOTREACHED */
51437836SJohn.Forte@Sun.COM 	return;
51447836SJohn.Forte@Sun.COM 
51457836SJohn.Forte@Sun.COM worker_mgmt_trigger_change:
51467836SJohn.Forte@Sun.COM 	ASSERT(workers_needed != stmf_nworkers_cur);
51477836SJohn.Forte@Sun.COM 	if (workers_needed > stmf_nworkers_cur) {
51487836SJohn.Forte@Sun.COM 		stmf_nworkers_needed = workers_needed;
51497836SJohn.Forte@Sun.COM 		for (i = stmf_nworkers_cur; i < workers_needed; i++) {
51507836SJohn.Forte@Sun.COM 			w = &stmf_workers[i];
51517836SJohn.Forte@Sun.COM 			w->worker_tid = thread_create(NULL, 0, stmf_worker_task,
51527836SJohn.Forte@Sun.COM 			    (void *)&stmf_workers[i], 0, &p0, TS_RUN,
51537836SJohn.Forte@Sun.COM 			    minclsyspri);
51547836SJohn.Forte@Sun.COM 		}
51557836SJohn.Forte@Sun.COM 		return;
51567836SJohn.Forte@Sun.COM 	}
51577836SJohn.Forte@Sun.COM 	/* At this point we know that we are decreasing the # of workers */
51587836SJohn.Forte@Sun.COM 	stmf_nworkers_accepting_cmds = workers_needed;
51597836SJohn.Forte@Sun.COM 	stmf_nworkers_needed = workers_needed;
51607836SJohn.Forte@Sun.COM 	/* Signal the workers that its time to quit */
51617836SJohn.Forte@Sun.COM 	for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
51627836SJohn.Forte@Sun.COM 		w = &stmf_workers[i];
51637836SJohn.Forte@Sun.COM 		ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED));
51647836SJohn.Forte@Sun.COM 		mutex_enter(&w->worker_lock);
51657836SJohn.Forte@Sun.COM 		w->worker_flags |= STMF_WORKER_TERMINATE;
51667836SJohn.Forte@Sun.COM 		if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
51677836SJohn.Forte@Sun.COM 			cv_signal(&w->worker_cv);
51687836SJohn.Forte@Sun.COM 		mutex_exit(&w->worker_lock);
51697836SJohn.Forte@Sun.COM 	}
51707836SJohn.Forte@Sun.COM }
51717836SJohn.Forte@Sun.COM 
51727836SJohn.Forte@Sun.COM /*
51737836SJohn.Forte@Sun.COM  * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private).
51747836SJohn.Forte@Sun.COM  * If all the data has been filled out, frees the xd and makes
51757836SJohn.Forte@Sun.COM  * db_lu_private NULL.
51767836SJohn.Forte@Sun.COM  */
51777836SJohn.Forte@Sun.COM void
51787836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf)
51797836SJohn.Forte@Sun.COM {
51807836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
51817836SJohn.Forte@Sun.COM 	uint8_t *p;
51827836SJohn.Forte@Sun.COM 	int i;
51837836SJohn.Forte@Sun.COM 	uint32_t s;
51847836SJohn.Forte@Sun.COM 
51857836SJohn.Forte@Sun.COM 	xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
51867836SJohn.Forte@Sun.COM 	dbuf->db_data_size = 0;
51877836SJohn.Forte@Sun.COM 	dbuf->db_relative_offset = xd->size_done;
51887836SJohn.Forte@Sun.COM 	for (i = 0; i < dbuf->db_sglist_length; i++) {
51897836SJohn.Forte@Sun.COM 		s = min(xd->size_left, dbuf->db_sglist[i].seg_length);
51907836SJohn.Forte@Sun.COM 		p = &xd->buf[xd->size_done];
51917836SJohn.Forte@Sun.COM 		bcopy(p, dbuf->db_sglist[i].seg_addr, s);
51927836SJohn.Forte@Sun.COM 		xd->size_left -= s;
51937836SJohn.Forte@Sun.COM 		xd->size_done += s;
51947836SJohn.Forte@Sun.COM 		dbuf->db_data_size += s;
51957836SJohn.Forte@Sun.COM 		if (xd->size_left == 0) {
51967836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
51977836SJohn.Forte@Sun.COM 			dbuf->db_lu_private = NULL;
51987836SJohn.Forte@Sun.COM 			return;
51997836SJohn.Forte@Sun.COM 		}
52007836SJohn.Forte@Sun.COM 	}
52017836SJohn.Forte@Sun.COM }
52027836SJohn.Forte@Sun.COM 
52037836SJohn.Forte@Sun.COM /* ARGSUSED */
52047836SJohn.Forte@Sun.COM stmf_status_t
52057836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task)
52067836SJohn.Forte@Sun.COM {
52077836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
52087836SJohn.Forte@Sun.COM }
52097836SJohn.Forte@Sun.COM 
52107836SJohn.Forte@Sun.COM void
52117836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
52127836SJohn.Forte@Sun.COM {
52137836SJohn.Forte@Sun.COM 	uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
52147836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
52157836SJohn.Forte@Sun.COM 	uint32_t sz, minsz;
52167836SJohn.Forte@Sun.COM 	uint8_t *p;
52177836SJohn.Forte@Sun.COM 	stmf_xfer_data_t *xd;
52187836SJohn.Forte@Sun.COM 	uint8_t inq_page_length = 31;
52197836SJohn.Forte@Sun.COM 
52207836SJohn.Forte@Sun.COM 	if (task->task_mgmt_function) {
52217836SJohn.Forte@Sun.COM 		stmf_scsilib_handle_task_mgmt(task);
52227836SJohn.Forte@Sun.COM 		return;
52237836SJohn.Forte@Sun.COM 	}
52247836SJohn.Forte@Sun.COM 
52257836SJohn.Forte@Sun.COM 	switch (cdbp[0]) {
52267836SJohn.Forte@Sun.COM 	case SCMD_INQUIRY:
52277836SJohn.Forte@Sun.COM 		/*
52287836SJohn.Forte@Sun.COM 		 * Basic protocol checks.  In addition, only reply to
52297836SJohn.Forte@Sun.COM 		 * standard inquiry.  Otherwise, the LU provider needs
52307836SJohn.Forte@Sun.COM 		 * to respond.
52317836SJohn.Forte@Sun.COM 		 */
52327836SJohn.Forte@Sun.COM 
52337836SJohn.Forte@Sun.COM 		if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) {
52347836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
52357836SJohn.Forte@Sun.COM 			    STMF_SAA_INVALID_FIELD_IN_CDB);
52367836SJohn.Forte@Sun.COM 			return;
52377836SJohn.Forte@Sun.COM 		}
52387836SJohn.Forte@Sun.COM 
52397836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
52407836SJohn.Forte@Sun.COM 		    (((uint32_t)cdbp[3]) << 8) | cdbp[4];
52417836SJohn.Forte@Sun.COM 
52427836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
52437836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
52447836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
52457836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
52467836SJohn.Forte@Sun.COM 		}
52477836SJohn.Forte@Sun.COM 
52487836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
52497836SJohn.Forte@Sun.COM 		    min(36, task->task_cmd_xfer_length));
52507836SJohn.Forte@Sun.COM 		minsz = 36;
52517836SJohn.Forte@Sun.COM 
52527836SJohn.Forte@Sun.COM 		if (sz == 0) {
52537836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
52547836SJohn.Forte@Sun.COM 			return;
52557836SJohn.Forte@Sun.COM 		}
52567836SJohn.Forte@Sun.COM 
52577836SJohn.Forte@Sun.COM 		if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) {
52587836SJohn.Forte@Sun.COM 			/*
52597836SJohn.Forte@Sun.COM 			 * Ignore any preallocated dbuf if the size is less
52607836SJohn.Forte@Sun.COM 			 * than 36. It will be freed during the task_free.
52617836SJohn.Forte@Sun.COM 			 */
52627836SJohn.Forte@Sun.COM 			dbuf = NULL;
52637836SJohn.Forte@Sun.COM 		}
52647836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
52657836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0);
52667836SJohn.Forte@Sun.COM 		if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) {
52677836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
52687836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
52697836SJohn.Forte@Sun.COM 			return;
52707836SJohn.Forte@Sun.COM 		}
52717836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = NULL;
52727836SJohn.Forte@Sun.COM 
52737836SJohn.Forte@Sun.COM 		p = dbuf->db_sglist[0].seg_addr;
52747836SJohn.Forte@Sun.COM 
52757836SJohn.Forte@Sun.COM 		/*
52767836SJohn.Forte@Sun.COM 		 * Standard inquiry handling only.
52777836SJohn.Forte@Sun.COM 		 */
52787836SJohn.Forte@Sun.COM 
52797836SJohn.Forte@Sun.COM 		bzero(p, inq_page_length + 5);
52807836SJohn.Forte@Sun.COM 
52817836SJohn.Forte@Sun.COM 		p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN;
52827836SJohn.Forte@Sun.COM 		p[2] = 5;
52837836SJohn.Forte@Sun.COM 		p[3] = 0x12;
52847836SJohn.Forte@Sun.COM 		p[4] = inq_page_length;
52857836SJohn.Forte@Sun.COM 		p[6] = 0x80;
52867836SJohn.Forte@Sun.COM 
52877836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+8, "SUN     ", 8);
52887836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+16, "COMSTAR	       ", 16);
52897836SJohn.Forte@Sun.COM 		(void) strncpy((char *)p+32, "1.0 ", 4);
52907836SJohn.Forte@Sun.COM 
52917836SJohn.Forte@Sun.COM 		dbuf->db_data_size = sz;
52927836SJohn.Forte@Sun.COM 		dbuf->db_relative_offset = 0;
52937836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
52947836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
52957836SJohn.Forte@Sun.COM 
52967836SJohn.Forte@Sun.COM 		return;
52977836SJohn.Forte@Sun.COM 
52987836SJohn.Forte@Sun.COM 	case SCMD_REPORT_LUNS:
52997836SJohn.Forte@Sun.COM 		task->task_cmd_xfer_length =
53007836SJohn.Forte@Sun.COM 		    ((((uint32_t)task->task_cdb[6]) << 24) |
53017836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[7]) << 16) |
53027836SJohn.Forte@Sun.COM 		    (((uint32_t)task->task_cdb[8]) << 8) |
53037836SJohn.Forte@Sun.COM 		    ((uint32_t)task->task_cdb[9]));
53047836SJohn.Forte@Sun.COM 
53057836SJohn.Forte@Sun.COM 		if (task->task_additional_flags &
53067836SJohn.Forte@Sun.COM 		    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
53077836SJohn.Forte@Sun.COM 			task->task_expected_xfer_length =
53087836SJohn.Forte@Sun.COM 			    task->task_cmd_xfer_length;
53097836SJohn.Forte@Sun.COM 		}
53107836SJohn.Forte@Sun.COM 
53117836SJohn.Forte@Sun.COM 		sz = min(task->task_expected_xfer_length,
53127836SJohn.Forte@Sun.COM 		    task->task_cmd_xfer_length);
53137836SJohn.Forte@Sun.COM 
53147836SJohn.Forte@Sun.COM 		if (sz < 16) {
53157836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_CHECK,
53168662SJordan.Vaughan@Sun.com 			    STMF_SAA_INVALID_FIELD_IN_CDB);
53177836SJohn.Forte@Sun.COM 			return;
53187836SJohn.Forte@Sun.COM 		}
53197836SJohn.Forte@Sun.COM 
53207836SJohn.Forte@Sun.COM 		iss = (stmf_i_scsi_session_t *)
53217836SJohn.Forte@Sun.COM 		    task->task_session->ss_stmf_private;
53227836SJohn.Forte@Sun.COM 		rw_enter(iss->iss_lockp, RW_WRITER);
53237836SJohn.Forte@Sun.COM 		xd = stmf_session_prepare_report_lun_data(iss->iss_sm);
53247836SJohn.Forte@Sun.COM 		rw_exit(iss->iss_lockp);
53257836SJohn.Forte@Sun.COM 
53267836SJohn.Forte@Sun.COM 		if (xd == NULL) {
53277836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53287836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
53297836SJohn.Forte@Sun.COM 			return;
53307836SJohn.Forte@Sun.COM 		}
53317836SJohn.Forte@Sun.COM 
53327836SJohn.Forte@Sun.COM 		sz = min(sz, xd->size_left);
53337836SJohn.Forte@Sun.COM 		xd->size_left = sz;
53347836SJohn.Forte@Sun.COM 		minsz = min(512, sz);
53357836SJohn.Forte@Sun.COM 
53367836SJohn.Forte@Sun.COM 		if (dbuf == NULL)
53377836SJohn.Forte@Sun.COM 			dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
53387836SJohn.Forte@Sun.COM 		if (dbuf == NULL) {
53397836SJohn.Forte@Sun.COM 			kmem_free(xd, xd->alloc_size);
53407836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53417836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
53427836SJohn.Forte@Sun.COM 			return;
53437836SJohn.Forte@Sun.COM 		}
53447836SJohn.Forte@Sun.COM 		dbuf->db_lu_private = xd;
53457836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
53467836SJohn.Forte@Sun.COM 
53477836SJohn.Forte@Sun.COM 		atomic_and_32(&iss->iss_flags,
53488662SJordan.Vaughan@Sun.com 		    ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
53497836SJohn.Forte@Sun.COM 		dbuf->db_flags = DB_DIRECTION_TO_RPORT;
53507836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
53517836SJohn.Forte@Sun.COM 		return;
53527836SJohn.Forte@Sun.COM 	}
53537836SJohn.Forte@Sun.COM 
53547836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE);
53557836SJohn.Forte@Sun.COM }
53567836SJohn.Forte@Sun.COM 
53577836SJohn.Forte@Sun.COM void
53587836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf)
53597836SJohn.Forte@Sun.COM {
53607836SJohn.Forte@Sun.COM 	if (dbuf->db_xfer_status != STMF_SUCCESS) {
53617836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
53627836SJohn.Forte@Sun.COM 		    dbuf->db_xfer_status, NULL);
53637836SJohn.Forte@Sun.COM 		return;
53647836SJohn.Forte@Sun.COM 	}
53657836SJohn.Forte@Sun.COM 	task->task_nbytes_transferred = dbuf->db_data_size;
53667836SJohn.Forte@Sun.COM 	if (dbuf->db_lu_private) {
53677836SJohn.Forte@Sun.COM 		/* There is more */
53687836SJohn.Forte@Sun.COM 		stmf_xd_to_dbuf(dbuf);
53697836SJohn.Forte@Sun.COM 		(void) stmf_xfer_data(task, dbuf, 0);
53707836SJohn.Forte@Sun.COM 		return;
53717836SJohn.Forte@Sun.COM 	}
53727836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
53737836SJohn.Forte@Sun.COM }
53747836SJohn.Forte@Sun.COM 
53757836SJohn.Forte@Sun.COM /* ARGSUSED */
53767836SJohn.Forte@Sun.COM void
53777836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task)
53787836SJohn.Forte@Sun.COM {
53797836SJohn.Forte@Sun.COM }
53807836SJohn.Forte@Sun.COM 
53817836SJohn.Forte@Sun.COM /* ARGSUSED */
53827836SJohn.Forte@Sun.COM void
53837836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task)
53847836SJohn.Forte@Sun.COM {
53857836SJohn.Forte@Sun.COM }
53867836SJohn.Forte@Sun.COM 
53877836SJohn.Forte@Sun.COM /* ARGSUSED */
53887836SJohn.Forte@Sun.COM stmf_status_t
53897836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
53907836SJohn.Forte@Sun.COM {
53917836SJohn.Forte@Sun.COM 	scsi_task_t *task = (scsi_task_t *)arg;
53927836SJohn.Forte@Sun.COM 	stmf_i_scsi_task_t *itask =
53938662SJordan.Vaughan@Sun.com 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
53947836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
53957836SJohn.Forte@Sun.COM 	int i;
53967836SJohn.Forte@Sun.COM 	uint8_t map;
53977836SJohn.Forte@Sun.COM 
53987836SJohn.Forte@Sun.COM 	ASSERT(abort_cmd == STMF_LU_ABORT_TASK);
53997836SJohn.Forte@Sun.COM 	if ((task->task_mgmt_function) && (itask->itask_flags &
54007836SJohn.Forte@Sun.COM 	    (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) {
54017836SJohn.Forte@Sun.COM 		switch (task->task_mgmt_function) {
54027836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK:
54037836SJohn.Forte@Sun.COM 		case TM_ABORT_TASK_SET:
54047836SJohn.Forte@Sun.COM 		case TM_CLEAR_TASK_SET:
54057836SJohn.Forte@Sun.COM 		case TM_LUN_RESET:
54067836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
54077836SJohn.Forte@Sun.COM 			break;
54087836SJohn.Forte@Sun.COM 		case TM_TARGET_RESET:
54097836SJohn.Forte@Sun.COM 		case TM_TARGET_COLD_RESET:
54107836SJohn.Forte@Sun.COM 		case TM_TARGET_WARM_RESET:
54117836SJohn.Forte@Sun.COM 			stmf_abort_target_reset(task);
54127836SJohn.Forte@Sun.COM 			break;
54137836SJohn.Forte@Sun.COM 		}
54147836SJohn.Forte@Sun.COM 		return (STMF_ABORT_SUCCESS);
54157836SJohn.Forte@Sun.COM 	}
54167836SJohn.Forte@Sun.COM 
54177836SJohn.Forte@Sun.COM 	/*
54187836SJohn.Forte@Sun.COM 	 * OK so its not a task mgmt. Make sure we free any xd sitting
54197836SJohn.Forte@Sun.COM 	 * inside any dbuf.
54207836SJohn.Forte@Sun.COM 	 */
54217836SJohn.Forte@Sun.COM 	if ((map = itask->itask_allocated_buf_map) != 0) {
54227836SJohn.Forte@Sun.COM 		for (i = 0; i < 4; i++) {
54237836SJohn.Forte@Sun.COM 			if ((map & 1) &&
54247836SJohn.Forte@Sun.COM 			    ((itask->itask_dbufs[i])->db_lu_private)) {
54257836SJohn.Forte@Sun.COM 				stmf_xfer_data_t *xd;
54267836SJohn.Forte@Sun.COM 				stmf_data_buf_t *dbuf;
54277836SJohn.Forte@Sun.COM 
54287836SJohn.Forte@Sun.COM 				dbuf = itask->itask_dbufs[i];
54297836SJohn.Forte@Sun.COM 				xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
54307836SJohn.Forte@Sun.COM 				dbuf->db_lu_private = NULL;
54317836SJohn.Forte@Sun.COM 				kmem_free(xd, xd->alloc_size);
54327836SJohn.Forte@Sun.COM 			}
54337836SJohn.Forte@Sun.COM 			map >>= 1;
54347836SJohn.Forte@Sun.COM 		}
54357836SJohn.Forte@Sun.COM 	}
54367836SJohn.Forte@Sun.COM 	return (STMF_ABORT_SUCCESS);
54377836SJohn.Forte@Sun.COM }
54387836SJohn.Forte@Sun.COM 
54397836SJohn.Forte@Sun.COM void
54407836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task)
54417836SJohn.Forte@Sun.COM {
54427836SJohn.Forte@Sun.COM 	/* Right now we only do this for handling task management functions */
54437836SJohn.Forte@Sun.COM 	ASSERT(task->task_mgmt_function);
54447836SJohn.Forte@Sun.COM 
54457836SJohn.Forte@Sun.COM 	switch (task->task_mgmt_function) {
54467836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK:
54477836SJohn.Forte@Sun.COM 	case TM_ABORT_TASK_SET:
54487836SJohn.Forte@Sun.COM 	case TM_CLEAR_TASK_SET:
54497836SJohn.Forte@Sun.COM 	case TM_LUN_RESET:
54507836SJohn.Forte@Sun.COM 		(void) stmf_lun_reset_poll(task->task_lu, task, 0);
54517836SJohn.Forte@Sun.COM 		return;
54527836SJohn.Forte@Sun.COM 	case TM_TARGET_RESET:
54537836SJohn.Forte@Sun.COM 	case TM_TARGET_COLD_RESET:
54547836SJohn.Forte@Sun.COM 	case TM_TARGET_WARM_RESET:
54557836SJohn.Forte@Sun.COM 		stmf_target_reset_poll(task);
54567836SJohn.Forte@Sun.COM 		return;
54577836SJohn.Forte@Sun.COM 	}
54587836SJohn.Forte@Sun.COM }
54597836SJohn.Forte@Sun.COM 
54607836SJohn.Forte@Sun.COM /* ARGSUSED */
54617836SJohn.Forte@Sun.COM void
54627836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg)
54637836SJohn.Forte@Sun.COM {
54647836SJohn.Forte@Sun.COM 	/* This function will never be called */
54657836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd);
54667836SJohn.Forte@Sun.COM }
54677836SJohn.Forte@Sun.COM 
54687836SJohn.Forte@Sun.COM void
54697836SJohn.Forte@Sun.COM stmf_dlun_init()
54707836SJohn.Forte@Sun.COM {
54717836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
54727836SJohn.Forte@Sun.COM 
54737836SJohn.Forte@Sun.COM 	dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0);
54747836SJohn.Forte@Sun.COM 	dlun0->lu_task_alloc = stmf_dlun0_task_alloc;
54757836SJohn.Forte@Sun.COM 	dlun0->lu_new_task = stmf_dlun0_new_task;
54767836SJohn.Forte@Sun.COM 	dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done;
54777836SJohn.Forte@Sun.COM 	dlun0->lu_send_status_done = stmf_dlun0_status_done;
54787836SJohn.Forte@Sun.COM 	dlun0->lu_task_free = stmf_dlun0_task_free;
54797836SJohn.Forte@Sun.COM 	dlun0->lu_abort = stmf_dlun0_abort;
54807836SJohn.Forte@Sun.COM 	dlun0->lu_task_poll = stmf_dlun0_task_poll;
54817836SJohn.Forte@Sun.COM 	dlun0->lu_ctl = stmf_dlun0_ctl;
54827836SJohn.Forte@Sun.COM 
54837836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
54847836SJohn.Forte@Sun.COM 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
54857836SJohn.Forte@Sun.COM }
54867836SJohn.Forte@Sun.COM 
54877836SJohn.Forte@Sun.COM stmf_status_t
54887836SJohn.Forte@Sun.COM stmf_dlun_fini()
54897836SJohn.Forte@Sun.COM {
54907836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
54917836SJohn.Forte@Sun.COM 
54927836SJohn.Forte@Sun.COM 	ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
54937836SJohn.Forte@Sun.COM 
54947836SJohn.Forte@Sun.COM 	ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
54957836SJohn.Forte@Sun.COM 	if (ilu->ilu_ntasks) {
54967836SJohn.Forte@Sun.COM 		stmf_i_scsi_task_t *itask, *nitask;
54977836SJohn.Forte@Sun.COM 
54987836SJohn.Forte@Sun.COM 		nitask = ilu->ilu_tasks;
54997836SJohn.Forte@Sun.COM 		do {
55007836SJohn.Forte@Sun.COM 			itask = nitask;
55017836SJohn.Forte@Sun.COM 			nitask = itask->itask_lu_next;
55027836SJohn.Forte@Sun.COM 			dlun0->lu_task_free(itask->itask_task);
55037836SJohn.Forte@Sun.COM 			stmf_free(itask->itask_task);
55047836SJohn.Forte@Sun.COM 		} while (nitask != NULL);
55057836SJohn.Forte@Sun.COM 
55067836SJohn.Forte@Sun.COM 	}
55077836SJohn.Forte@Sun.COM 	stmf_free(dlun0);
55087836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
55097836SJohn.Forte@Sun.COM }
55107836SJohn.Forte@Sun.COM 
55117836SJohn.Forte@Sun.COM void
55127836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task)
55137836SJohn.Forte@Sun.COM {
55147836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
55158662SJordan.Vaughan@Sun.com 	    task->task_session->ss_stmf_private;
55167836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
55177836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
55187836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
55197836SJohn.Forte@Sun.COM 	int i;
55207836SJohn.Forte@Sun.COM 
55217836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
55227836SJohn.Forte@Sun.COM 
55237836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
55247836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
55257836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
55267836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
55277836SJohn.Forte@Sun.COM 			continue;
55287836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
55297836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
55307836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
55317836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
55327836SJohn.Forte@Sun.COM 		}
55337836SJohn.Forte@Sun.COM 	}
55347836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
55357836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
55367836SJohn.Forte@Sun.COM }
55377836SJohn.Forte@Sun.COM 
55387836SJohn.Forte@Sun.COM /*
55397836SJohn.Forte@Sun.COM  * The return value is only used by function managing target reset.
55407836SJohn.Forte@Sun.COM  */
55417836SJohn.Forte@Sun.COM stmf_status_t
55427836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset)
55437836SJohn.Forte@Sun.COM {
55447836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
55457836SJohn.Forte@Sun.COM 	int ntasks_pending;
55467836SJohn.Forte@Sun.COM 
55477836SJohn.Forte@Sun.COM 	ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free;
55487836SJohn.Forte@Sun.COM 	/*
55497836SJohn.Forte@Sun.COM 	 * This function is also used during Target reset. The idea is that
55507836SJohn.Forte@Sun.COM 	 * once all the commands are aborted, call the LU's reset entry
55517836SJohn.Forte@Sun.COM 	 * point (abort entry point with a reset flag). But if this Task
55527836SJohn.Forte@Sun.COM 	 * mgmt is running on this LU then all the tasks cannot be aborted.
55537836SJohn.Forte@Sun.COM 	 * one task (this task) will still be running which is OK.
55547836SJohn.Forte@Sun.COM 	 */
55557836SJohn.Forte@Sun.COM 	if ((ntasks_pending == 0) || ((task->task_lu == lu) &&
55567836SJohn.Forte@Sun.COM 	    (ntasks_pending == 1))) {
55577836SJohn.Forte@Sun.COM 		stmf_status_t ret;
55587836SJohn.Forte@Sun.COM 
55597836SJohn.Forte@Sun.COM 		if ((task->task_mgmt_function == TM_LUN_RESET) ||
55607836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_RESET) ||
55617836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_WARM_RESET) ||
55627836SJohn.Forte@Sun.COM 		    (task->task_mgmt_function == TM_TARGET_COLD_RESET)) {
55637836SJohn.Forte@Sun.COM 			ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0);
55647836SJohn.Forte@Sun.COM 		} else {
55657836SJohn.Forte@Sun.COM 			ret = STMF_SUCCESS;
55667836SJohn.Forte@Sun.COM 		}
55677836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
55687836SJohn.Forte@Sun.COM 			atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
55697836SJohn.Forte@Sun.COM 		}
55707836SJohn.Forte@Sun.COM 		if (target_reset) {
55717836SJohn.Forte@Sun.COM 			return (ret);
55727836SJohn.Forte@Sun.COM 		}
55737836SJohn.Forte@Sun.COM 		if (ret == STMF_SUCCESS) {
55747836SJohn.Forte@Sun.COM 			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
55757836SJohn.Forte@Sun.COM 			return (ret);
55767836SJohn.Forte@Sun.COM 		}
55777836SJohn.Forte@Sun.COM 		if (ret != STMF_BUSY) {
55787836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL);
55797836SJohn.Forte@Sun.COM 			return (ret);
55807836SJohn.Forte@Sun.COM 		}
55817836SJohn.Forte@Sun.COM 	}
55827836SJohn.Forte@Sun.COM 
55837836SJohn.Forte@Sun.COM 	if (target_reset) {
55847836SJohn.Forte@Sun.COM 		/* Tell target reset polling code that we are not done */
55857836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
55867836SJohn.Forte@Sun.COM 	}
55877836SJohn.Forte@Sun.COM 
55887836SJohn.Forte@Sun.COM 	if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
55897836SJohn.Forte@Sun.COM 	    != STMF_SUCCESS) {
55907836SJohn.Forte@Sun.COM 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
55917836SJohn.Forte@Sun.COM 		    STMF_ALLOC_FAILURE, NULL);
55927836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
55937836SJohn.Forte@Sun.COM 	}
55947836SJohn.Forte@Sun.COM 
55957836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
55967836SJohn.Forte@Sun.COM }
55977836SJohn.Forte@Sun.COM 
55987836SJohn.Forte@Sun.COM void
55997836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task)
56007836SJohn.Forte@Sun.COM {
56017836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
56028662SJordan.Vaughan@Sun.com 	    task->task_session->ss_stmf_private;
56037836SJohn.Forte@Sun.COM 	stmf_lun_map_t *lm;
56047836SJohn.Forte@Sun.COM 	stmf_lun_map_ent_t *lm_ent;
56057836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
56067836SJohn.Forte@Sun.COM 	stmf_status_t ret;
56077836SJohn.Forte@Sun.COM 	int i;
56087836SJohn.Forte@Sun.COM 	int not_done = 0;
56097836SJohn.Forte@Sun.COM 
56107836SJohn.Forte@Sun.COM 	ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
56117836SJohn.Forte@Sun.COM 
56127836SJohn.Forte@Sun.COM 	rw_enter(iss->iss_lockp, RW_READER);
56137836SJohn.Forte@Sun.COM 	lm = iss->iss_sm;
56147836SJohn.Forte@Sun.COM 	for (i = 0; i < lm->lm_nentries; i++) {
56157836SJohn.Forte@Sun.COM 		if (lm->lm_plus[i] == NULL)
56167836SJohn.Forte@Sun.COM 			continue;
56177836SJohn.Forte@Sun.COM 		lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
56187836SJohn.Forte@Sun.COM 		ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
56197836SJohn.Forte@Sun.COM 		if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
56207836SJohn.Forte@Sun.COM 			rw_exit(iss->iss_lockp);
56217836SJohn.Forte@Sun.COM 			ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1);
56227836SJohn.Forte@Sun.COM 			rw_enter(iss->iss_lockp, RW_READER);
56237836SJohn.Forte@Sun.COM 			if (ret == STMF_SUCCESS)
56247836SJohn.Forte@Sun.COM 				continue;
56257836SJohn.Forte@Sun.COM 			not_done = 1;
56267836SJohn.Forte@Sun.COM 			if (ret != STMF_BUSY) {
56277836SJohn.Forte@Sun.COM 				rw_exit(iss->iss_lockp);
56287836SJohn.Forte@Sun.COM 				stmf_abort(STMF_QUEUE_TASK_ABORT, task,
56297836SJohn.Forte@Sun.COM 				    STMF_ABORTED, NULL);
56307836SJohn.Forte@Sun.COM 				return;
56317836SJohn.Forte@Sun.COM 			}
56327836SJohn.Forte@Sun.COM 		}
56337836SJohn.Forte@Sun.COM 	}
56347836SJohn.Forte@Sun.COM 	rw_exit(iss->iss_lockp);
56357836SJohn.Forte@Sun.COM 
56367836SJohn.Forte@Sun.COM 	if (not_done) {
56377836SJohn.Forte@Sun.COM 		if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
56387836SJohn.Forte@Sun.COM 		    != STMF_SUCCESS) {
56397836SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
56407836SJohn.Forte@Sun.COM 			    STMF_ALLOC_FAILURE, NULL);
56417836SJohn.Forte@Sun.COM 			return;
56427836SJohn.Forte@Sun.COM 		}
56437836SJohn.Forte@Sun.COM 		return;
56447836SJohn.Forte@Sun.COM 	}
56457836SJohn.Forte@Sun.COM 
56467836SJohn.Forte@Sun.COM 	atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
56477836SJohn.Forte@Sun.COM 
56487836SJohn.Forte@Sun.COM 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
56497836SJohn.Forte@Sun.COM }
56507836SJohn.Forte@Sun.COM 
56517836SJohn.Forte@Sun.COM stmf_status_t
56527836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid)
56537836SJohn.Forte@Sun.COM {
56547836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
56557836SJohn.Forte@Sun.COM 
56567836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56577836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56587836SJohn.Forte@Sun.COM 	}
56597836SJohn.Forte@Sun.COM 
56607836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid);
56617836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56627836SJohn.Forte@Sun.COM }
56637836SJohn.Forte@Sun.COM 
56647836SJohn.Forte@Sun.COM stmf_status_t
56657836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid)
56667836SJohn.Forte@Sun.COM {
56677836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
56687836SJohn.Forte@Sun.COM 
56697836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
56707836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl);
56717836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
56727836SJohn.Forte@Sun.COM 	}
56737836SJohn.Forte@Sun.COM 
56747836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56757836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56767836SJohn.Forte@Sun.COM 	}
56777836SJohn.Forte@Sun.COM 
56787836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid);
56797836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56807836SJohn.Forte@Sun.COM }
56817836SJohn.Forte@Sun.COM 
56827836SJohn.Forte@Sun.COM stmf_status_t
56837836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid)
56847836SJohn.Forte@Sun.COM {
56857836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
56868662SJordan.Vaughan@Sun.com 	    (stmf_i_local_port_t *)lport->lport_stmf_private;
56877836SJohn.Forte@Sun.COM 
56887836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
56897836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
56907836SJohn.Forte@Sun.COM 	}
56917836SJohn.Forte@Sun.COM 
56927836SJohn.Forte@Sun.COM 	STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid);
56937836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
56947836SJohn.Forte@Sun.COM }
56957836SJohn.Forte@Sun.COM 
56967836SJohn.Forte@Sun.COM stmf_status_t
56977836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid)
56987836SJohn.Forte@Sun.COM {
56997836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport =
57008662SJordan.Vaughan@Sun.com 	    (stmf_i_local_port_t *)lport->lport_stmf_private;
57017836SJohn.Forte@Sun.COM 
57027836SJohn.Forte@Sun.COM 	if (eventid == STMF_EVENT_ALL) {
57037836SJohn.Forte@Sun.COM 		STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl);
57047836SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
57057836SJohn.Forte@Sun.COM 	}
57067836SJohn.Forte@Sun.COM 
57077836SJohn.Forte@Sun.COM 	if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
57087836SJohn.Forte@Sun.COM 		return (STMF_INVALID_ARG);
57097836SJohn.Forte@Sun.COM 	}
57107836SJohn.Forte@Sun.COM 
57117836SJohn.Forte@Sun.COM 	STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid);
57127836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
57137836SJohn.Forte@Sun.COM }
57147836SJohn.Forte@Sun.COM 
57157836SJohn.Forte@Sun.COM void
57167836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags)
57177836SJohn.Forte@Sun.COM {
57187836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) &&
57197836SJohn.Forte@Sun.COM 	    (ilu->ilu_lu->lu_event_handler != NULL)) {
57207836SJohn.Forte@Sun.COM 		ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags);
57217836SJohn.Forte@Sun.COM 	}
57227836SJohn.Forte@Sun.COM }
57237836SJohn.Forte@Sun.COM 
57247836SJohn.Forte@Sun.COM void
57257836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg,
57267836SJohn.Forte@Sun.COM 				uint32_t flags)
57277836SJohn.Forte@Sun.COM {
57287836SJohn.Forte@Sun.COM 	if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) &&
57297836SJohn.Forte@Sun.COM 	    (ilport->ilport_lport->lport_event_handler != NULL)) {
57307836SJohn.Forte@Sun.COM 		ilport->ilport_lport->lport_event_handler(
57317836SJohn.Forte@Sun.COM 		    ilport->ilport_lport, eventid, arg, flags);
57327836SJohn.Forte@Sun.COM 	}
57337836SJohn.Forte@Sun.COM }
57347836SJohn.Forte@Sun.COM 
57357836SJohn.Forte@Sun.COM void
57367836SJohn.Forte@Sun.COM stmf_svc_init()
57377836SJohn.Forte@Sun.COM {
57387836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
57397836SJohn.Forte@Sun.COM 		return;
57407836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1,
57417836SJohn.Forte@Sun.COM 	    TASKQ_DEFAULTPRI, 0);
57427836SJohn.Forte@Sun.COM 	(void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq,
57437836SJohn.Forte@Sun.COM 	    stmf_svc, 0, DDI_SLEEP);
57447836SJohn.Forte@Sun.COM }
57457836SJohn.Forte@Sun.COM 
57467836SJohn.Forte@Sun.COM stmf_status_t
57477836SJohn.Forte@Sun.COM stmf_svc_fini()
57487836SJohn.Forte@Sun.COM {
57497836SJohn.Forte@Sun.COM 	uint32_t i;
57507836SJohn.Forte@Sun.COM 
57517836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
57527836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) {
57537836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE;
57547836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
57557836SJohn.Forte@Sun.COM 	}
57567836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
57577836SJohn.Forte@Sun.COM 
57587836SJohn.Forte@Sun.COM 	/* Wait for 5 seconds */
57597836SJohn.Forte@Sun.COM 	for (i = 0; i < 500; i++) {
57607836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
57617836SJohn.Forte@Sun.COM 			delay(drv_usectohz(10000));
57627836SJohn.Forte@Sun.COM 		else
57637836SJohn.Forte@Sun.COM 			break;
57647836SJohn.Forte@Sun.COM 	}
57657836SJohn.Forte@Sun.COM 	if (i == 500)
57667836SJohn.Forte@Sun.COM 		return (STMF_BUSY);
57677836SJohn.Forte@Sun.COM 
57687836SJohn.Forte@Sun.COM 	ddi_taskq_destroy(stmf_state.stmf_svc_taskq);
57697836SJohn.Forte@Sun.COM 
57707836SJohn.Forte@Sun.COM 	return (STMF_SUCCESS);
57717836SJohn.Forte@Sun.COM }
57727836SJohn.Forte@Sun.COM 
57737836SJohn.Forte@Sun.COM /* ARGSUSED */
57747836SJohn.Forte@Sun.COM void
57757836SJohn.Forte@Sun.COM stmf_svc(void *arg)
57767836SJohn.Forte@Sun.COM {
57777836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req, **preq;
57787836SJohn.Forte@Sun.COM 	clock_t td;
57797836SJohn.Forte@Sun.COM 	clock_t	drain_start, drain_next = 0;
57807836SJohn.Forte@Sun.COM 	clock_t	timing_start, timing_next = 0;
57817836SJohn.Forte@Sun.COM 	clock_t worker_delay = 0;
57827836SJohn.Forte@Sun.COM 	int deq;
57837836SJohn.Forte@Sun.COM 	stmf_lu_t *lu;
57847836SJohn.Forte@Sun.COM 	stmf_i_lu_t *ilu;
57857836SJohn.Forte@Sun.COM 	stmf_local_port_t *lport;
57867836SJohn.Forte@Sun.COM 	stmf_i_local_port_t *ilport, *next_ilport;
57877836SJohn.Forte@Sun.COM 	stmf_i_scsi_session_t *iss;
57887836SJohn.Forte@Sun.COM 
57897836SJohn.Forte@Sun.COM 	td = drv_usectohz(20000);
57907836SJohn.Forte@Sun.COM 
57917836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
57927836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE;
57937836SJohn.Forte@Sun.COM 
57947836SJohn.Forte@Sun.COM stmf_svc_loop:
57957836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) {
57967836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &=
57977836SJohn.Forte@Sun.COM 		    ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE);
57987836SJohn.Forte@Sun.COM 		mutex_exit(&stmf_state.stmf_lock);
57997836SJohn.Forte@Sun.COM 		return;
58007836SJohn.Forte@Sun.COM 	}
58017836SJohn.Forte@Sun.COM 
58027836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active) {
58037836SJohn.Forte@Sun.COM 		int waitq_add = 0;
58047836SJohn.Forte@Sun.COM 		req = stmf_state.stmf_svc_active;
58057836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_active = req->svc_next;
58067836SJohn.Forte@Sun.COM 
58077836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
58087836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
58097836SJohn.Forte@Sun.COM 			/* Fallthrough */
58107836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
58117836SJohn.Forte@Sun.COM 			/* Fallthrough */
58127836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
58137836SJohn.Forte@Sun.COM 			/* Nothing to do */
58147836SJohn.Forte@Sun.COM 			waitq_add = 1;
58157836SJohn.Forte@Sun.COM 			break;
58167836SJohn.Forte@Sun.COM 
58177836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
58187836SJohn.Forte@Sun.COM 			/* Remove all mappings of this LU */
58197836SJohn.Forte@Sun.COM 			stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj);
58207836SJohn.Forte@Sun.COM 			/* Kill all the pending I/Os for this LU */
58217836SJohn.Forte@Sun.COM 			mutex_exit(&stmf_state.stmf_lock);
58227836SJohn.Forte@Sun.COM 			stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL,
58238662SJordan.Vaughan@Sun.com 			    STMF_ABORTED);
58247836SJohn.Forte@Sun.COM 			mutex_enter(&stmf_state.stmf_lock);
58257836SJohn.Forte@Sun.COM 			waitq_add = 1;
58267836SJohn.Forte@Sun.COM 			break;
58277836SJohn.Forte@Sun.COM 		default:
58287836SJohn.Forte@Sun.COM 			cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d",
58297836SJohn.Forte@Sun.COM 			    req->svc_cmd);
58307836SJohn.Forte@Sun.COM 		}
58317836SJohn.Forte@Sun.COM 
58327836SJohn.Forte@Sun.COM 		if (waitq_add) {
58337836SJohn.Forte@Sun.COM 			/* Put it in the wait queue */
58347836SJohn.Forte@Sun.COM 			req->svc_next = stmf_state.stmf_svc_waiting;
58357836SJohn.Forte@Sun.COM 			stmf_state.stmf_svc_waiting = req;
58367836SJohn.Forte@Sun.COM 		}
58377836SJohn.Forte@Sun.COM 	}
58387836SJohn.Forte@Sun.COM 
58397836SJohn.Forte@Sun.COM 	/* The waiting list is not going to be modified by anybody else */
58407836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
58417836SJohn.Forte@Sun.COM 
58427836SJohn.Forte@Sun.COM 	for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) {
58437836SJohn.Forte@Sun.COM 		req = *preq;
58447836SJohn.Forte@Sun.COM 		deq = 0;
58457836SJohn.Forte@Sun.COM 		switch (req->svc_cmd) {
58467836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_ONLINE:
58477836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
58487836SJohn.Forte@Sun.COM 			deq = 1;
58497836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
58507836SJohn.Forte@Sun.COM 			break;
58517836SJohn.Forte@Sun.COM 
58527836SJohn.Forte@Sun.COM 		case STMF_CMD_LU_OFFLINE:
58537836SJohn.Forte@Sun.COM 			lu = (stmf_lu_t *)req->svc_obj;
58547836SJohn.Forte@Sun.COM 			ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
58557836SJohn.Forte@Sun.COM 			if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
58567836SJohn.Forte@Sun.COM 				break;
58577836SJohn.Forte@Sun.COM 			deq = 1;
58587836SJohn.Forte@Sun.COM 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
58597836SJohn.Forte@Sun.COM 			break;
58607836SJohn.Forte@Sun.COM 
58617836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_OFFLINE:
58627836SJohn.Forte@Sun.COM 			/* Fallthrough */
58637836SJohn.Forte@Sun.COM 		case STMF_CMD_LPORT_ONLINE:
58647836SJohn.Forte@Sun.COM 			lport = (stmf_local_port_t *)req->svc_obj;
58657836SJohn.Forte@Sun.COM 			deq = 1;
58667836SJohn.Forte@Sun.COM 			lport->lport_ctl(lport, req->svc_cmd, &req->svc_info);
58677836SJohn.Forte@Sun.COM 			break;
58687836SJohn.Forte@Sun.COM 		}
58697836SJohn.Forte@Sun.COM 		if (deq) {
58707836SJohn.Forte@Sun.COM 			*preq = req->svc_next;
58717836SJohn.Forte@Sun.COM 			kmem_free(req, req->svc_req_alloc_size);
58727836SJohn.Forte@Sun.COM 		} else {
58737836SJohn.Forte@Sun.COM 			preq = &req->svc_next;
58747836SJohn.Forte@Sun.COM 		}
58757836SJohn.Forte@Sun.COM 	}
58767836SJohn.Forte@Sun.COM 
58777836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
58787836SJohn.Forte@Sun.COM 	if (stmf_state.stmf_svc_active == NULL) {
58797836SJohn.Forte@Sun.COM 		/* Do timeouts */
58807836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
58817836SJohn.Forte@Sun.COM 		    ((!timing_next) || (ddi_get_lbolt() >= timing_next))) {
58827836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
58837836SJohn.Forte@Sun.COM 				/* we are starting a new round */
58847836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_timing =
58857836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
58867836SJohn.Forte@Sun.COM 				timing_start = ddi_get_lbolt();
58877836SJohn.Forte@Sun.COM 			}
58887836SJohn.Forte@Sun.COM 			stmf_check_ilu_timing();
58897836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_timing) {
58907836SJohn.Forte@Sun.COM 				/* we finished a complete round */
58917836SJohn.Forte@Sun.COM 				timing_next =
58927836SJohn.Forte@Sun.COM 				    timing_start + drv_usectohz(5*1000*1000);
58937836SJohn.Forte@Sun.COM 			} else {
58947836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
58957836SJohn.Forte@Sun.COM 				timing_next =
58967836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
58977836SJohn.Forte@Sun.COM 			}
58987836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
58997836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
59007836SJohn.Forte@Sun.COM 		}
59017836SJohn.Forte@Sun.COM 		/* Check if there are free tasks to clear */
59027836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_nlus &&
59037836SJohn.Forte@Sun.COM 		    ((!drain_next) || (ddi_get_lbolt() >= drain_next))) {
59047836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
59057836SJohn.Forte@Sun.COM 				/* we are starting a new round */
59067836SJohn.Forte@Sun.COM 				stmf_state.stmf_svc_ilu_draining =
59077836SJohn.Forte@Sun.COM 				    stmf_state.stmf_ilulist;
59087836SJohn.Forte@Sun.COM 				drain_start = ddi_get_lbolt();
59097836SJohn.Forte@Sun.COM 			}
59107836SJohn.Forte@Sun.COM 			stmf_check_freetask();
59117836SJohn.Forte@Sun.COM 			if (!stmf_state.stmf_svc_ilu_draining) {
59127836SJohn.Forte@Sun.COM 				/* we finished a complete round */
59137836SJohn.Forte@Sun.COM 				drain_next =
59147836SJohn.Forte@Sun.COM 				    drain_start + drv_usectohz(10*1000*1000);
59157836SJohn.Forte@Sun.COM 			} else {
59167836SJohn.Forte@Sun.COM 				/* we still have some ilu items to check */
59177836SJohn.Forte@Sun.COM 				drain_next =
59187836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() + drv_usectohz(1*1000*1000);
59197836SJohn.Forte@Sun.COM 			}
59207836SJohn.Forte@Sun.COM 			if (stmf_state.stmf_svc_active)
59217836SJohn.Forte@Sun.COM 				goto stmf_svc_loop;
59227836SJohn.Forte@Sun.COM 		}
59237836SJohn.Forte@Sun.COM 
59247836SJohn.Forte@Sun.COM 		/* Check if we need to run worker_mgmt */
59257836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > worker_delay) {
59267836SJohn.Forte@Sun.COM 			stmf_worker_mgmt();
59277836SJohn.Forte@Sun.COM 			worker_delay = ddi_get_lbolt() +
59287836SJohn.Forte@Sun.COM 			    stmf_worker_mgmt_delay;
59297836SJohn.Forte@Sun.COM 		}
59307836SJohn.Forte@Sun.COM 
59317836SJohn.Forte@Sun.COM 		/* Check if any active session got its 1st LUN */
59327836SJohn.Forte@Sun.COM 		if (stmf_state.stmf_process_initial_luns) {
59337836SJohn.Forte@Sun.COM 			int stmf_level = 0;
59347836SJohn.Forte@Sun.COM 			int port_level;
59357836SJohn.Forte@Sun.COM 			for (ilport = stmf_state.stmf_ilportlist; ilport;
59367836SJohn.Forte@Sun.COM 			    ilport = next_ilport) {
59377836SJohn.Forte@Sun.COM 				next_ilport = ilport->ilport_next;
59387836SJohn.Forte@Sun.COM 				if ((ilport->ilport_flags &
59397836SJohn.Forte@Sun.COM 				    ILPORT_SS_GOT_INITIAL_LUNS) == 0) {
59407836SJohn.Forte@Sun.COM 					continue;
59417836SJohn.Forte@Sun.COM 				}
59427836SJohn.Forte@Sun.COM 				port_level = 0;
59437836SJohn.Forte@Sun.COM 				rw_enter(&ilport->ilport_lock, RW_READER);
59447836SJohn.Forte@Sun.COM 				for (iss = ilport->ilport_ss_list; iss;
59457836SJohn.Forte@Sun.COM 				    iss = iss->iss_next) {
59467836SJohn.Forte@Sun.COM 					if ((iss->iss_flags &
59477836SJohn.Forte@Sun.COM 					    ISS_GOT_INITIAL_LUNS) == 0) {
59487836SJohn.Forte@Sun.COM 						continue;
59497836SJohn.Forte@Sun.COM 					}
59507836SJohn.Forte@Sun.COM 					port_level++;
59517836SJohn.Forte@Sun.COM 					stmf_level++;
59527836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
59538662SJordan.Vaughan@Sun.com 					    ~ISS_GOT_INITIAL_LUNS);
59547836SJohn.Forte@Sun.COM 					atomic_or_32(&iss->iss_flags,
59558662SJordan.Vaughan@Sun.com 					    ISS_EVENT_ACTIVE);
59567836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
59577836SJohn.Forte@Sun.COM 					mutex_exit(&stmf_state.stmf_lock);
59587836SJohn.Forte@Sun.COM 					stmf_generate_lport_event(ilport,
59597836SJohn.Forte@Sun.COM 					    LPORT_EVENT_INITIAL_LUN_MAPPED,
59607836SJohn.Forte@Sun.COM 					    iss->iss_ss, 0);
59617836SJohn.Forte@Sun.COM 					atomic_and_32(&iss->iss_flags,
59628662SJordan.Vaughan@Sun.com 					    ~ISS_EVENT_ACTIVE);
59637836SJohn.Forte@Sun.COM 					mutex_enter(&stmf_state.stmf_lock);
59647836SJohn.Forte@Sun.COM 					/*
59657836SJohn.Forte@Sun.COM 					 * scan all the ilports again as the
59667836SJohn.Forte@Sun.COM 					 * ilport list might have changed.
59677836SJohn.Forte@Sun.COM 					 */
59687836SJohn.Forte@Sun.COM 					next_ilport =
59698662SJordan.Vaughan@Sun.com 					    stmf_state.stmf_ilportlist;
59707836SJohn.Forte@Sun.COM 					break;
59717836SJohn.Forte@Sun.COM 				}
59727836SJohn.Forte@Sun.COM 				if (port_level == 0) {
59737836SJohn.Forte@Sun.COM 					atomic_and_32(&ilport->ilport_flags,
59748662SJordan.Vaughan@Sun.com 					    ~ILPORT_SS_GOT_INITIAL_LUNS);
59757836SJohn.Forte@Sun.COM 				}
59767836SJohn.Forte@Sun.COM 				/* drop the lock if we are holding it. */
59777836SJohn.Forte@Sun.COM 				if (rw_lock_held(&ilport->ilport_lock))
59787836SJohn.Forte@Sun.COM 					rw_exit(&ilport->ilport_lock);
59797836SJohn.Forte@Sun.COM 
59807836SJohn.Forte@Sun.COM 				/* Max 4 session at a time */
59817836SJohn.Forte@Sun.COM 				if (stmf_level >= 4) {
59827836SJohn.Forte@Sun.COM 					break;
59837836SJohn.Forte@Sun.COM 				}
59847836SJohn.Forte@Sun.COM 			}
59857836SJohn.Forte@Sun.COM 			if (stmf_level == 0) {
59867836SJohn.Forte@Sun.COM 				stmf_state.stmf_process_initial_luns = 0;
59877836SJohn.Forte@Sun.COM 			}
59887836SJohn.Forte@Sun.COM 		}
59897836SJohn.Forte@Sun.COM 
59907836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE;
59917836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock,
59927836SJohn.Forte@Sun.COM 		    ddi_get_lbolt() + td);
59937836SJohn.Forte@Sun.COM 		stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
59947836SJohn.Forte@Sun.COM 	}
59957836SJohn.Forte@Sun.COM 	goto stmf_svc_loop;
59967836SJohn.Forte@Sun.COM }
59977836SJohn.Forte@Sun.COM 
59987836SJohn.Forte@Sun.COM void
59997836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
60007836SJohn.Forte@Sun.COM {
60017836SJohn.Forte@Sun.COM 	stmf_svc_req_t *req;
60027836SJohn.Forte@Sun.COM 	int s;
60037836SJohn.Forte@Sun.COM 
60047836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&stmf_state.stmf_lock));
60057836SJohn.Forte@Sun.COM 	s = sizeof (stmf_svc_req_t);
60067836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
60077836SJohn.Forte@Sun.COM 		s += strlen(info->st_additional_info) + 1;
60087836SJohn.Forte@Sun.COM 	}
60097836SJohn.Forte@Sun.COM 	req = kmem_zalloc(s, KM_SLEEP);
60107836SJohn.Forte@Sun.COM 
60117836SJohn.Forte@Sun.COM 	req->svc_cmd = cmd;
60127836SJohn.Forte@Sun.COM 	req->svc_obj = obj;
60137836SJohn.Forte@Sun.COM 	req->svc_info.st_rflags = info->st_rflags;
60147836SJohn.Forte@Sun.COM 	if (info->st_additional_info) {
60157836SJohn.Forte@Sun.COM 		req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req,
60167836SJohn.Forte@Sun.COM 		    sizeof (stmf_svc_req_t)));
60177836SJohn.Forte@Sun.COM 		(void) strcpy(req->svc_info.st_additional_info,
60187836SJohn.Forte@Sun.COM 		    info->st_additional_info);
60197836SJohn.Forte@Sun.COM 	}
60207836SJohn.Forte@Sun.COM 	req->svc_req_alloc_size = s;
60217836SJohn.Forte@Sun.COM 
60227836SJohn.Forte@Sun.COM 	mutex_enter(&stmf_state.stmf_lock);
60237836SJohn.Forte@Sun.COM 	req->svc_next = stmf_state.stmf_svc_active;
60247836SJohn.Forte@Sun.COM 	stmf_state.stmf_svc_active = req;
60257836SJohn.Forte@Sun.COM 	if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) {
60267836SJohn.Forte@Sun.COM 		cv_signal(&stmf_state.stmf_cv);
60277836SJohn.Forte@Sun.COM 	}
60287836SJohn.Forte@Sun.COM 	mutex_exit(&stmf_state.stmf_lock);
60297836SJohn.Forte@Sun.COM }
60307836SJohn.Forte@Sun.COM 
60317836SJohn.Forte@Sun.COM void
60327836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...)
60337836SJohn.Forte@Sun.COM {
60347836SJohn.Forte@Sun.COM 	va_list args;
60357836SJohn.Forte@Sun.COM 	char tbuf[160];
60367836SJohn.Forte@Sun.COM 	int len;
60377836SJohn.Forte@Sun.COM 
60387836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
60397836SJohn.Forte@Sun.COM 		return;
60407836SJohn.Forte@Sun.COM 	len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "",
60417836SJohn.Forte@Sun.COM 	    ddi_get_lbolt());
60427836SJohn.Forte@Sun.COM 	va_start(args, fmt);
60437836SJohn.Forte@Sun.COM 	len += vsnprintf(tbuf + len, 158 - len, fmt, args);
60447836SJohn.Forte@Sun.COM 	va_end(args);
60457836SJohn.Forte@Sun.COM 
60467836SJohn.Forte@Sun.COM 	if (len > 158) {
60477836SJohn.Forte@Sun.COM 		len = 158;
60487836SJohn.Forte@Sun.COM 	}
60497836SJohn.Forte@Sun.COM 	tbuf[len++] = '\n';
60507836SJohn.Forte@Sun.COM 	tbuf[len] = 0;
60517836SJohn.Forte@Sun.COM 
60527836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
60537836SJohn.Forte@Sun.COM 	bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1);
60547836SJohn.Forte@Sun.COM 	trace_buf_curndx += len;
60557836SJohn.Forte@Sun.COM 	if (trace_buf_curndx > (trace_buf_size - 320))
60567836SJohn.Forte@Sun.COM 		trace_buf_curndx = 0;
60577836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
60587836SJohn.Forte@Sun.COM }
60597836SJohn.Forte@Sun.COM 
60607836SJohn.Forte@Sun.COM void
60617836SJohn.Forte@Sun.COM stmf_trace_clear()
60627836SJohn.Forte@Sun.COM {
60637836SJohn.Forte@Sun.COM 	if (!stmf_trace_on)
60647836SJohn.Forte@Sun.COM 		return;
60657836SJohn.Forte@Sun.COM 	mutex_enter(&trace_buf_lock);
60667836SJohn.Forte@Sun.COM 	trace_buf_curndx = 0;
60677836SJohn.Forte@Sun.COM 	if (trace_buf_size > 0)
60687836SJohn.Forte@Sun.COM 		stmf_trace_buf[0] = 0;
60697836SJohn.Forte@Sun.COM 	mutex_exit(&trace_buf_lock);
60707836SJohn.Forte@Sun.COM }
60717836SJohn.Forte@Sun.COM 
60727836SJohn.Forte@Sun.COM static void
60737836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info)
60747836SJohn.Forte@Sun.COM {
60757836SJohn.Forte@Sun.COM 	stmf_state_change_info_t	 change_info;
60767836SJohn.Forte@Sun.COM 	void				*ctl_private;
60777836SJohn.Forte@Sun.COM 	uint32_t			 ctl_cmd;
60787836SJohn.Forte@Sun.COM 	int				msg = 0;
60797836SJohn.Forte@Sun.COM 
60807836SJohn.Forte@Sun.COM 	stmf_trace("FROM STMF", "abort_task_offline called for %s: %s",
60817836SJohn.Forte@Sun.COM 	    offline_lu ? "LU" : "LPORT", info ? info : "no additional info");
60827836SJohn.Forte@Sun.COM 	change_info.st_additional_info = info;
60837836SJohn.Forte@Sun.COM 	if (offline_lu) {
60847836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
60857836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LU_ABORT;
60867836SJohn.Forte@Sun.COM 		ctl_private = task->task_lu;
60877836SJohn.Forte@Sun.COM 		if (((stmf_i_lu_t *)
60887836SJohn.Forte@Sun.COM 		    task->task_lu->lu_stmf_private)->ilu_state ==
60897836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
60907836SJohn.Forte@Sun.COM 			msg = 1;
60917836SJohn.Forte@Sun.COM 		}
60927836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LU_OFFLINE;
60937836SJohn.Forte@Sun.COM 	} else {
60947836SJohn.Forte@Sun.COM 		change_info.st_rflags = STMF_RFLAG_RESET |
60957836SJohn.Forte@Sun.COM 		    STMF_RFLAG_LPORT_ABORT;
60967836SJohn.Forte@Sun.COM 		ctl_private = task->task_lport;
60977836SJohn.Forte@Sun.COM 		if (((stmf_i_local_port_t *)
60987836SJohn.Forte@Sun.COM 		    task->task_lport->lport_stmf_private)->ilport_state ==
60997836SJohn.Forte@Sun.COM 		    STMF_STATE_ONLINE) {
61007836SJohn.Forte@Sun.COM 			msg = 1;
61017836SJohn.Forte@Sun.COM 		}
61027836SJohn.Forte@Sun.COM 		ctl_cmd = STMF_CMD_LPORT_OFFLINE;
61037836SJohn.Forte@Sun.COM 	}
61047836SJohn.Forte@Sun.COM 
61057836SJohn.Forte@Sun.COM 	if (msg) {
61067836SJohn.Forte@Sun.COM 		stmf_trace(0, "Calling stmf_ctl to offline %s : %s",
61077836SJohn.Forte@Sun.COM 		    offline_lu ? "LU" : "LPORT", info ? info :
61087836SJohn.Forte@Sun.COM 		    "<no additional info>");
61097836SJohn.Forte@Sun.COM 	}
61107836SJohn.Forte@Sun.COM 	(void) stmf_ctl(ctl_cmd, ctl_private, &change_info);
61117836SJohn.Forte@Sun.COM }
6112