xref: /illumos-gate/usr/src/uts/common/io/sbp2/sbp2.c (revision 8c067cfd)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f5488aa8Sbharding  * Common Development and Distribution License (the "License").
6f5488aa8Sbharding  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*8c067cfdSAlan Perry  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * SBP2 module
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/errno.h>
317c478bd9Sstevel@tonic-gate #include <sys/cred.h>
327c478bd9Sstevel@tonic-gate #include <sys/conf.h>
33*8c067cfdSAlan Perry #include <sys/disp.h>
347c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/stream.h>
377c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
387c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
397c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <sys/sbp2/impl.h>
437c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1212.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* target routines */
467c478bd9Sstevel@tonic-gate static void	sbp2_tgt_init_sobj(sbp2_tgt_t *);
477c478bd9Sstevel@tonic-gate static void	sbp2_tgt_fini_sobj(sbp2_tgt_t *);
487c478bd9Sstevel@tonic-gate static int	sbp2_tgt_init_params(sbp2_tgt_t *);
497c478bd9Sstevel@tonic-gate static int	sbp2_tgt_init_luns(sbp2_tgt_t *, int);
507c478bd9Sstevel@tonic-gate static void	sbp2_tgt_fini_luns(sbp2_tgt_t *);
517c478bd9Sstevel@tonic-gate static int	sbp2_tgt_init_bus(sbp2_tgt_t *);
527c478bd9Sstevel@tonic-gate static void	sbp2_tgt_fini_bus(sbp2_tgt_t *);
537c478bd9Sstevel@tonic-gate static int	sbp2_tgt_mgt_request(sbp2_tgt_t *, int *);
547c478bd9Sstevel@tonic-gate static int	sbp2_tgt_task_mgt_request(sbp2_tgt_t *, uint16_t, int, uint64_t,
557c478bd9Sstevel@tonic-gate 		int *);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* lun routines */
587c478bd9Sstevel@tonic-gate static void	sbp2_lun_logout_orb(sbp2_lun_t *, sbp2_tgt_t *, int *);
597c478bd9Sstevel@tonic-gate static boolean_t sbp2_lun_accepting_tasks(sbp2_lun_t *);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* session routines */
627c478bd9Sstevel@tonic-gate static int	sbp2_ses_init(sbp2_ses_t **, sbp2_lun_t *,
637c478bd9Sstevel@tonic-gate 		void (*)(void *, sbp2_task_t *), void *);
647c478bd9Sstevel@tonic-gate static void	sbp2_ses_fini(sbp2_ses_t *);
657c478bd9Sstevel@tonic-gate static sbp2_task_t *sbp2_ses_orbp2task(sbp2_ses_t *, uint64_t);
667c478bd9Sstevel@tonic-gate static void	sbp2_ses_append_task(sbp2_ses_t *, sbp2_task_t *);
677c478bd9Sstevel@tonic-gate static void	sbp2_ses_reset_pending_tasks(sbp2_ses_t *, uint16_t);
687c478bd9Sstevel@tonic-gate static int	sbp2_ses_reconnect_orb(sbp2_ses_t *, int *);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* orb alloc routines */
717c478bd9Sstevel@tonic-gate static sbp2_bus_buf_t *sbp2_orb_freelist_get(sbp2_lun_t *, sbp2_task_t *, int);
727c478bd9Sstevel@tonic-gate static int	sbp2_orb_freelist_put(sbp2_lun_t *, sbp2_bus_buf_t *);
737c478bd9Sstevel@tonic-gate static void	sbp2_orb_freelist_destroy(sbp2_lun_t *);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /* fetch agent routines */
767c478bd9Sstevel@tonic-gate static int	sbp2_agent_init(sbp2_agent_t *, uint64_t, sbp2_tgt_t *tp);
777c478bd9Sstevel@tonic-gate static void	sbp2_agent_fini(sbp2_agent_t *);
787c478bd9Sstevel@tonic-gate static void	sbp2_agent_acquire_locked(sbp2_agent_t *);
797c478bd9Sstevel@tonic-gate static void	sbp2_agent_release_locked(sbp2_agent_t *);
807c478bd9Sstevel@tonic-gate static void	sbp2_agent_acquire(sbp2_agent_t *);
817c478bd9Sstevel@tonic-gate static void	sbp2_agent_release(sbp2_agent_t *);
827c478bd9Sstevel@tonic-gate static int	sbp2_agent_keepalive(sbp2_agent_t *, int *);
837c478bd9Sstevel@tonic-gate static int	sbp2_agent_doorbell(sbp2_agent_t *, int *);
847c478bd9Sstevel@tonic-gate static int	sbp2_agent_write_orbp(sbp2_agent_t *, uint64_t, int *);
857c478bd9Sstevel@tonic-gate static int	sbp2_agent_reset(sbp2_agent_t *, int *);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* callbacks and timeouts */
887c478bd9Sstevel@tonic-gate static void	sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **);
897c478bd9Sstevel@tonic-gate static void	sbp2_task_timeout(void *);
907c478bd9Sstevel@tonic-gate static void	sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* other */
937c478bd9Sstevel@tonic-gate static void	sbp2_mgt_agent_acquire(sbp2_tgt_t *);
947c478bd9Sstevel@tonic-gate static void	sbp2_mgt_agent_release(sbp2_tgt_t *);
957c478bd9Sstevel@tonic-gate static void	sbp2_fetch_agent_acquire(sbp2_ses_t *);
967c478bd9Sstevel@tonic-gate static void	sbp2_fetch_agent_release(sbp2_ses_t *);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate static struct modlmisc sbp2_modlmisc = {
1017c478bd9Sstevel@tonic-gate 	&mod_miscops,		/* module type */
102f5488aa8Sbharding 	"Serial Bus Protocol 2 module" /* module name */
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static struct modlinkage sbp2_modlinkage = {
1067c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&sbp2_modlmisc, NULL
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /* tunables */
1107c478bd9Sstevel@tonic-gate int	sbp2_submit_reset_nretries = 3;
1117c478bd9Sstevel@tonic-gate clock_t	sbp2_submit_reset_delay = 10;	/* microsec */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate int	sbp2_write_orbp_nretries = 3;
1147c478bd9Sstevel@tonic-gate clock_t	sbp2_write_orbp_delay = 10;	/* microsec */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab msgb))
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * --- loadable module entry points
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  */
1237c478bd9Sstevel@tonic-gate int
_init(void)1247c478bd9Sstevel@tonic-gate _init(void)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	return (mod_install(&sbp2_modlinkage));
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate int
_fini(void)1317c478bd9Sstevel@tonic-gate _fini(void)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	return (mod_remove(&sbp2_modlinkage));
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1387c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	return (mod_info(&sbp2_modlinkage, modinfop));
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  *
1457c478bd9Sstevel@tonic-gate  * --- target routines
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  */
1487c478bd9Sstevel@tonic-gate int
sbp2_tgt_init(void * bus_hdl,sbp2_bus_t * bus,int maxluns,sbp2_tgt_t ** tpp)1497c478bd9Sstevel@tonic-gate sbp2_tgt_init(void *bus_hdl, sbp2_bus_t *bus, int maxluns, sbp2_tgt_t **tpp)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp;
1527c478bd9Sstevel@tonic-gate 	int		ret;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	tp = kmem_zalloc(sizeof (sbp2_tgt_t), KM_SLEEP);
1557c478bd9Sstevel@tonic-gate 	tp->t_bus = bus;
1567c478bd9Sstevel@tonic-gate 	tp->t_bus_hdl = bus_hdl;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	sbp2_tgt_init_sobj(tp);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_cfgrom_parse(tp, &tp->t_cfgrom)) != SBP2_SUCCESS) {
1617c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_sobj(tp);
1627c478bd9Sstevel@tonic-gate 		kmem_free(tp, sizeof (sbp2_tgt_t));
1637c478bd9Sstevel@tonic-gate 		return (SBP2_ECFGROM);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_init_params(tp)) != SBP2_SUCCESS) {
1677c478bd9Sstevel@tonic-gate 		sbp2_cfgrom_free(tp, &tp->t_cfgrom);
1687c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_sobj(tp);
1697c478bd9Sstevel@tonic-gate 		kmem_free(tp, sizeof (sbp2_tgt_t));
1707c478bd9Sstevel@tonic-gate 		return (ret);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_init_luns(tp, maxluns)) != SBP2_SUCCESS) {
1747c478bd9Sstevel@tonic-gate 		sbp2_cfgrom_free(tp, &tp->t_cfgrom);
1757c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_sobj(tp);
1767c478bd9Sstevel@tonic-gate 		kmem_free(tp, sizeof (sbp2_tgt_t));
1777c478bd9Sstevel@tonic-gate 		return (ret);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_init_bus(tp)) != SBP2_SUCCESS) {
1817c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_luns(tp);
1827c478bd9Sstevel@tonic-gate 		sbp2_cfgrom_free(tp, &tp->t_cfgrom);
1837c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_sobj(tp);
1847c478bd9Sstevel@tonic-gate 		kmem_free(tp, sizeof (sbp2_tgt_t));
1857c478bd9Sstevel@tonic-gate 		return (ret);
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	*tpp = tp;
1897c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate void
sbp2_tgt_fini(sbp2_tgt_t * tp)1937c478bd9Sstevel@tonic-gate sbp2_tgt_fini(sbp2_tgt_t *tp)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	sbp2_tgt_fini_bus(tp);
1967c478bd9Sstevel@tonic-gate 	sbp2_tgt_fini_luns(tp);
1977c478bd9Sstevel@tonic-gate 	sbp2_cfgrom_free(tp, &tp->t_cfgrom);
1987c478bd9Sstevel@tonic-gate 	sbp2_tgt_fini_sobj(tp);
1997c478bd9Sstevel@tonic-gate 	kmem_free(tp, sizeof (sbp2_tgt_t));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static void
sbp2_tgt_init_sobj(sbp2_tgt_t * tp)2037c478bd9Sstevel@tonic-gate sbp2_tgt_init_sobj(sbp2_tgt_t *tp)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	mutex_init(&tp->t_mutex, NULL, MUTEX_DRIVER, NULL);
2067c478bd9Sstevel@tonic-gate 	cv_init(&tp->t_mgt_agent_cv, NULL, CV_DRIVER, NULL);
2077c478bd9Sstevel@tonic-gate 	cv_init(&tp->t_mgt_status_cv, NULL, CV_DRIVER, NULL);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static void
sbp2_tgt_fini_sobj(sbp2_tgt_t * tp)2117c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(sbp2_tgt_t *tp)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	cv_destroy(&tp->t_mgt_status_cv);
2147c478bd9Sstevel@tonic-gate 	cv_destroy(&tp->t_mgt_agent_cv);
2157c478bd9Sstevel@tonic-gate 	mutex_destroy(&tp->t_mutex);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate static int
sbp2_tgt_init_params(sbp2_tgt_t * tp)2197c478bd9Sstevel@tonic-gate sbp2_tgt_init_params(sbp2_tgt_t *tp)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root;
2227c478bd9Sstevel@tonic-gate 	sbp2_cfgrom_ent_t *ent;
2237c478bd9Sstevel@tonic-gate 	uint32_t	q;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/* MANAGEMENT_AGENT */
2267c478bd9Sstevel@tonic-gate 	if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_MGT_AGENT,
2277c478bd9Sstevel@tonic-gate 	    SBP2_KV_MGT_AGENT, 0)) == NULL) {
2287c478bd9Sstevel@tonic-gate 		return (SBP2_ECFGROM);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	tp->t_mgt_agent = SBP2_CSR_BASE(tp) + ent->ce_data.offset * 4;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/* Unit_Characteristics */
2337c478bd9Sstevel@tonic-gate 	if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_UNCHAR,
2347c478bd9Sstevel@tonic-gate 	    SBP2_KV_UNCHAR, 0)) == NULL) {
2357c478bd9Sstevel@tonic-gate 		return (SBP2_ECFGROM);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 	q = ent->ce_data.imm;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/* units of 500 ms -> ms */
2407c478bd9Sstevel@tonic-gate 	tp->t_mot = ((q & SBP2_UNCHAR_MOT) >> SBP2_UNCHAR_MOT_SHIFT) * 500;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	/* quadlets -> bytes */
2437c478bd9Sstevel@tonic-gate 	tp->t_orb_size = (q & SBP2_UNCHAR_ORB_SIZE) * 4;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* some devices return incorrect values */
2467c478bd9Sstevel@tonic-gate 	if (tp->t_mot < SBP2_MOT_MIN) {
2477c478bd9Sstevel@tonic-gate 		tp->t_mot = SBP2_MOT_DFLT;
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	if (tp->t_orb_size < SBP2_ORB_SIZE_MIN) {
2507c478bd9Sstevel@tonic-gate 		tp->t_orb_size = SBP2_ORB_SIZE_MIN;
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2587c478bd9Sstevel@tonic-gate static int
sbp2_tgt_init_luns(sbp2_tgt_t * tp,int maxluns)2597c478bd9Sstevel@tonic-gate sbp2_tgt_init_luns(sbp2_tgt_t *tp, int maxluns)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root;
2627c478bd9Sstevel@tonic-gate 	sbp2_cfgrom_ent_t *ent;
2637c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp;
2647c478bd9Sstevel@tonic-gate 	uint32_t	q;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	ASSERT(tp->t_nluns == 0);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	tp->t_lun = kmem_zalloc(maxluns * sizeof (sbp2_lun_t), KM_SLEEP);
2697c478bd9Sstevel@tonic-gate 	tp->t_nluns_alloc = maxluns;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/* search for Logical_Unit_Number's */
2727c478bd9Sstevel@tonic-gate 	for (tp->t_nluns = 0; tp->t_nluns < maxluns; tp->t_nluns++) {
2737c478bd9Sstevel@tonic-gate 		if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_LUN,
2747c478bd9Sstevel@tonic-gate 		    SBP2_KV_LUN, tp->t_nluns)) == NULL) {
2757c478bd9Sstevel@tonic-gate 			break;
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 		q = ent->ce_data.imm;
2787c478bd9Sstevel@tonic-gate 		lp = &tp->t_lun[tp->t_nluns];
2797c478bd9Sstevel@tonic-gate 		lp->l_tgt = tp;
2807c478bd9Sstevel@tonic-gate 		lp->l_lun = q & SBP2_LUN_NUM;
2817c478bd9Sstevel@tonic-gate 		lp->l_type = (q & SBP2_LUN_TYPE) >> SBP2_LUN_TYPE_SHIFT;
2827c478bd9Sstevel@tonic-gate 		mutex_init(&lp->l_orb_freelist.bl_mutex, NULL, MUTEX_DRIVER,
2837c478bd9Sstevel@tonic-gate 		    NULL);
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	if (tp->t_nluns > 0) {
2877c478bd9Sstevel@tonic-gate 		return (SBP2_SUCCESS);
2887c478bd9Sstevel@tonic-gate 	} else {
2897c478bd9Sstevel@tonic-gate 		kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t));
2907c478bd9Sstevel@tonic-gate 		return (SBP2_ECFGROM);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate static void
sbp2_tgt_fini_luns(sbp2_tgt_t * tp)2977c478bd9Sstevel@tonic-gate sbp2_tgt_fini_luns(sbp2_tgt_t *tp)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	int		i;
3007c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* destroy each lun */
3037c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->t_nluns; i++) {
3047c478bd9Sstevel@tonic-gate 		lp = &tp->t_lun[i];
3057c478bd9Sstevel@tonic-gate 		sbp2_orb_freelist_destroy(lp);
3067c478bd9Sstevel@tonic-gate 		mutex_destroy(&lp->l_orb_freelist.bl_mutex);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t));
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * initialize bus buffers and commands
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate static int
sbp2_tgt_init_bus(sbp2_tgt_t * tp)3167c478bd9Sstevel@tonic-gate sbp2_tgt_init_bus(sbp2_tgt_t *tp)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	int		ret;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * We serialize management requests and reuse the same buffers.
3227c478bd9Sstevel@tonic-gate 	 *
3237c478bd9Sstevel@tonic-gate 	 * mgt ORB
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	tp->t_mgt_orb_buf.bb_len =
3267c478bd9Sstevel@tonic-gate 	    SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_mgt_orb_t));
3277c478bd9Sstevel@tonic-gate 	tp->t_mgt_orb_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD;
3287c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_orb_buf)) != SBP2_SUCCESS) {
3297c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_bus(tp);
3307c478bd9Sstevel@tonic-gate 		return (ret);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/*
3347c478bd9Sstevel@tonic-gate 	 * mgt status FIFO
3357c478bd9Sstevel@tonic-gate 	 */
3367c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_fifo_buf.bb_len = sizeof (sbp2_status_t);
3377c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED;
3387c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_fifo_buf.bb_wb_cb = sbp2_mgt_status_fifo_wb_cb;
3397c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_fifo_buf.bb_sbp2_priv = tp;
3407c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_status_fifo_buf)) !=
3417c478bd9Sstevel@tonic-gate 	    SBP2_SUCCESS) {
3427c478bd9Sstevel@tonic-gate 		return (ret);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/*
3467c478bd9Sstevel@tonic-gate 	 * login response
3477c478bd9Sstevel@tonic-gate 	 */
3487c478bd9Sstevel@tonic-gate 	tp->t_mgt_login_resp_buf.bb_len =
3497c478bd9Sstevel@tonic-gate 	    SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_login_resp_t));
3507c478bd9Sstevel@tonic-gate 	/*
3517c478bd9Sstevel@tonic-gate 	 * read-only should have been sufficient here, but it causes
3527c478bd9Sstevel@tonic-gate 	 * DVMA errors on Grover, while read/write works just fine
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	tp->t_mgt_login_resp_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RW;
3557c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_login_resp_buf)) !=
3567c478bd9Sstevel@tonic-gate 	    SBP2_SUCCESS) {
3577c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_bus(tp);
3587c478bd9Sstevel@tonic-gate 		return (ret);
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	/*
3627c478bd9Sstevel@tonic-gate 	 * allocate bus commands
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_CMD(tp, &tp->t_mgt_cmd, 0)) != SBP2_SUCCESS) {
3657c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_bus(tp);
3667c478bd9Sstevel@tonic-gate 		return (ret);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	if ((tp->t_mgt_cmd_data = allocb(8, BPRI_HI)) == NULL) {
3697c478bd9Sstevel@tonic-gate 		sbp2_tgt_fini_bus(tp);
3707c478bd9Sstevel@tonic-gate 		return (SBP2_ENOMEM);
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate static void
sbp2_tgt_fini_bus(sbp2_tgt_t * tp)3777c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(sbp2_tgt_t *tp)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	if (tp->t_mgt_status_fifo_buf.bb_hdl != NULL) {
3807c478bd9Sstevel@tonic-gate 		SBP2_FREE_BUF(tp, &tp->t_mgt_status_fifo_buf);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	if (tp->t_mgt_orb_buf.bb_hdl != NULL) {
3837c478bd9Sstevel@tonic-gate 		SBP2_FREE_BUF(tp, &tp->t_mgt_orb_buf);
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 	if (tp->t_mgt_login_resp_buf.bb_hdl != NULL) {
3867c478bd9Sstevel@tonic-gate 		SBP2_FREE_BUF(tp, &tp->t_mgt_login_resp_buf);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	if (tp->t_mgt_cmd) {
3897c478bd9Sstevel@tonic-gate 		SBP2_FREE_CMD(tp, tp->t_mgt_cmd);
390f2b7ce3eSartem 		tp->t_mgt_cmd = NULL;
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	if (tp->t_mgt_cmd_data) {
3937c478bd9Sstevel@tonic-gate 		freeb(tp->t_mgt_cmd_data);
394f2b7ce3eSartem 		tp->t_mgt_cmd_data = NULL;
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate void
sbp2_tgt_disconnect(sbp2_tgt_t * tp)3997c478bd9Sstevel@tonic-gate sbp2_tgt_disconnect(sbp2_tgt_t *tp)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	sbp2_tgt_fini_bus(tp);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate int
sbp2_tgt_reconnect(sbp2_tgt_t * tp)4057c478bd9Sstevel@tonic-gate sbp2_tgt_reconnect(sbp2_tgt_t *tp)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	return (sbp2_tgt_init_bus(tp));
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * send mgt ORB and wait for status
4127c478bd9Sstevel@tonic-gate  *
4137c478bd9Sstevel@tonic-gate  * mgt agent should be acquired
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static int
sbp2_tgt_mgt_request(sbp2_tgt_t * tp,int * berr)4167c478bd9Sstevel@tonic-gate sbp2_tgt_mgt_request(sbp2_tgt_t *tp, int *berr)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	clock_t		until;
4197c478bd9Sstevel@tonic-gate 	int		ret;
4207c478bd9Sstevel@tonic-gate 
421f5488aa8Sbharding 	/*
422f5488aa8Sbharding 	 * When a ctl operation happens from HAL - this could be 0!
423f5488aa8Sbharding 	 * This will happen when a device is disconected and then
424f5488aa8Sbharding 	 * reconnected. Note  there are problems with not being able
425f5488aa8Sbharding 	 * to detach/eject a target before unplugging. That can cause
426f5488aa8Sbharding 	 * this to happen... This problem needs some work elseware!
427f5488aa8Sbharding 	 * This just prevents a needless panic. If we return failure
428f5488aa8Sbharding 	 * the target ultimatly will recover and is usable.
429f5488aa8Sbharding 	 */
430f5488aa8Sbharding 	if (tp->t_mgt_cmd_data == 0) {
431f5488aa8Sbharding 		return (SBP2_FAILURE);
432f5488aa8Sbharding 	}
433f5488aa8Sbharding 
4347c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_rcvd = B_FALSE;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/* write ORB address into MANAGEMENT_AGENT */
4377c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(tp->t_mgt_cmd_data->b_rptr, tp->t_mgt_orb_buf.bb_baddr,
4387c478bd9Sstevel@tonic-gate 	    0);
4397c478bd9Sstevel@tonic-gate 	tp->t_mgt_cmd_data->b_wptr = tp->t_mgt_cmd_data->b_rptr + 8;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_WB(tp, tp->t_mgt_cmd, tp->t_mgt_agent,
4427c478bd9Sstevel@tonic-gate 	    tp->t_mgt_cmd_data, 8, berr)) != SBP2_SUCCESS) {
4437c478bd9Sstevel@tonic-gate 		return (ret);
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/* wait for login response */
4477c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
4487c478bd9Sstevel@tonic-gate 	until = ddi_get_lbolt() + drv_usectohz(tp->t_mot * 1000);
4497c478bd9Sstevel@tonic-gate 	ret = 1;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	while (!tp->t_mgt_status_rcvd && (ret > 0)) {
4527c478bd9Sstevel@tonic-gate 		ret = cv_timedwait(&tp->t_mgt_status_cv, &tp->t_mutex, until);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (!tp->t_mgt_status_rcvd) {
4567c478bd9Sstevel@tonic-gate 		ret = SBP2_ETIMEOUT;
4577c478bd9Sstevel@tonic-gate 	} else if ((tp->t_mgt_status.st_param & SBP2_ST_RESP) ==
4587c478bd9Sstevel@tonic-gate 	    SBP2_ST_RESP_COMPLETE) {
4597c478bd9Sstevel@tonic-gate 		ret = SBP2_SUCCESS;
4607c478bd9Sstevel@tonic-gate 	} else {
4617c478bd9Sstevel@tonic-gate 		ret = SBP2_FAILURE;
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	return (ret);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * Send task management request, one of:
4707c478bd9Sstevel@tonic-gate  *
4717c478bd9Sstevel@tonic-gate  *	ABORT TASK, ABORT TASK SET, LOGICAL UNIT RESET, TARGET RESET
4727c478bd9Sstevel@tonic-gate  */
4737c478bd9Sstevel@tonic-gate static int
sbp2_tgt_task_mgt_request(sbp2_tgt_t * tp,uint16_t id,int func,uint64_t orbp,int * berr)4747c478bd9Sstevel@tonic-gate sbp2_tgt_task_mgt_request(sbp2_tgt_t *tp, uint16_t id, int func, uint64_t orbp,
4757c478bd9Sstevel@tonic-gate     int *berr)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	sbp2_task_mgt_orb_t *torb;
4787c478bd9Sstevel@tonic-gate 	int		ret;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_acquire(tp);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	torb = (sbp2_task_mgt_orb_t *)tp->t_mgt_orb_buf.bb_kaddr;
4837c478bd9Sstevel@tonic-gate 	bzero(torb, sizeof (sbp2_task_mgt_orb_t));
4847c478bd9Sstevel@tonic-gate 	SBP2_ORBP_SET(torb->to_orb, orbp);
4857c478bd9Sstevel@tonic-gate 	torb->to_params = SBP2_SWAP16(func | SBP2_ORB_NOTIFY |
4867c478bd9Sstevel@tonic-gate 	    SBP2_ORB_RQ_FMT_SBP2);
4877c478bd9Sstevel@tonic-gate 	torb->to_login_id = SBP2_SWAP16(id);
4887c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(torb->to_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr,
4897c478bd9Sstevel@tonic-gate 	    0);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	ret = sbp2_tgt_mgt_request(tp, berr);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_release(tp);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	return (ret);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate int
sbp2_tgt_reset(sbp2_tgt_t * tp,int * berr)4997c478bd9Sstevel@tonic-gate sbp2_tgt_reset(sbp2_tgt_t *tp, int *berr)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp = &tp->t_lun[0];
5027c478bd9Sstevel@tonic-gate 	int		ret;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/* issue TARGET RESET */
5057c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id,
5067c478bd9Sstevel@tonic-gate 	    SBP2_ORB_MGT_FUNC_TARGET_RESET, 0, berr)) != SBP2_SUCCESS) {
5077c478bd9Sstevel@tonic-gate 		return (ret);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate int
sbp2_tgt_get_cfgrom(sbp2_tgt_t * tp,sbp2_cfgrom_t ** crpp)5147c478bd9Sstevel@tonic-gate sbp2_tgt_get_cfgrom(sbp2_tgt_t *tp, sbp2_cfgrom_t **crpp)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	*crpp = &tp->t_cfgrom;
5177c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate int
sbp2_tgt_get_lun_cnt(sbp2_tgt_t * tp)5217c478bd9Sstevel@tonic-gate sbp2_tgt_get_lun_cnt(sbp2_tgt_t *tp)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	return (tp->t_nluns);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate sbp2_lun_t *
sbp2_tgt_get_lun(sbp2_tgt_t * tp,int num)5277c478bd9Sstevel@tonic-gate sbp2_tgt_get_lun(sbp2_tgt_t *tp, int num)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	if (num < tp->t_nluns) {
5307c478bd9Sstevel@tonic-gate 		return (&tp->t_lun[num]);
5317c478bd9Sstevel@tonic-gate 	} else {
5327c478bd9Sstevel@tonic-gate 		return (NULL);
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate  *
5387c478bd9Sstevel@tonic-gate  * --- lun routines
5397c478bd9Sstevel@tonic-gate  *
5407c478bd9Sstevel@tonic-gate  */
5417c478bd9Sstevel@tonic-gate int
sbp2_lun_reset(sbp2_lun_t * lp,int * berr)5427c478bd9Sstevel@tonic-gate sbp2_lun_reset(sbp2_lun_t *lp, int *berr)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
5457c478bd9Sstevel@tonic-gate 	sbp2_ses_t	*sp = lp->l_ses;
5467c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
5477c478bd9Sstevel@tonic-gate 	int		ret;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/* issue LOGICAL UNIT RESET */
5507c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id,
5517c478bd9Sstevel@tonic-gate 	    SBP2_ORB_MGT_FUNC_LUN_RESET, 0, berr)) != SBP2_SUCCESS) {
5527c478bd9Sstevel@tonic-gate 		return (ret);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	/* mark all pending tasks reset and notify the driver */
5567c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
5577c478bd9Sstevel@tonic-gate 	for (task = sp->s_task_head; task != NULL; task = task->ts_next) {
5587c478bd9Sstevel@tonic-gate 		if (task->ts_state < SBP2_TASK_COMP) {
5597c478bd9Sstevel@tonic-gate 			task->ts_error = SBP2_TASK_ERR_LUN_RESET;
5607c478bd9Sstevel@tonic-gate 			task->ts_state = SBP2_TASK_COMP;
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	sp->s_status_cb(sp->s_status_cb_arg, NULL);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate int
sbp2_lun_login(sbp2_lun_t * lp,sbp2_ses_t ** spp,void (* cb)(void *,sbp2_task_t *),void * cb_arg,int * berr)5717c478bd9Sstevel@tonic-gate sbp2_lun_login(sbp2_lun_t *lp, sbp2_ses_t **spp,
5727c478bd9Sstevel@tonic-gate     void (*cb)(void *, sbp2_task_t *), void *cb_arg, int *berr)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
5757c478bd9Sstevel@tonic-gate 	sbp2_ses_t	*sp;
5767c478bd9Sstevel@tonic-gate 	sbp2_login_orb_t *lorb;
5777c478bd9Sstevel@tonic-gate 	int		ret;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (cb == NULL) {
5807c478bd9Sstevel@tonic-gate 		return (SBP2_EINVAL);
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	/* multiple sessions not supported yet */
5847c478bd9Sstevel@tonic-gate 	if (lp->l_ses != NULL) {
5857c478bd9Sstevel@tonic-gate 		return (SBP2_EALREADY);
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_ses_init(&sp, lp, cb, cb_arg)) != SBP2_SUCCESS) {
5897c478bd9Sstevel@tonic-gate 		return (ret);
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 	lp->l_ses = sp;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_acquire(tp);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/* prepare login ORB */
5967c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
5977c478bd9Sstevel@tonic-gate 	lorb = (sbp2_login_orb_t *)tp->t_mgt_orb_buf.bb_kaddr;
5987c478bd9Sstevel@tonic-gate 	bzero(lorb, sizeof (sbp2_login_orb_t));
5997c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(lorb->lo_resp, tp->t_mgt_login_resp_buf.bb_baddr, 0);
6007c478bd9Sstevel@tonic-gate 	lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGIN |
6017c478bd9Sstevel@tonic-gate 	    SBP2_ORB_LOGIN_EXCL | SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2);
6027c478bd9Sstevel@tonic-gate 	lorb->lo_lun = SBP2_SWAP16(lp->l_lun);
6037c478bd9Sstevel@tonic-gate 	lorb->lo_resp_len = SBP2_SWAP16(tp->t_mgt_login_resp_buf.bb_len);
6047c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(lorb->lo_status_fifo, sp->s_status_fifo_buf.bb_baddr, 0);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	bzero(tp->t_mgt_login_resp_buf.bb_kaddr, sizeof (sbp2_login_resp_t));
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	lp->l_logged_in = B_FALSE;
6097c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* send request */
6127c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) {
6137c478bd9Sstevel@tonic-gate 		sbp2_mgt_agent_release(tp);
6147c478bd9Sstevel@tonic-gate 		sbp2_ses_fini(lp->l_ses);
6157c478bd9Sstevel@tonic-gate 		lp->l_ses = NULL;
6167c478bd9Sstevel@tonic-gate 		return (ret);
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/* retrieve response data (XXX sanity checks?) */
6207c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
6217c478bd9Sstevel@tonic-gate 	(void) SBP2_SYNC_BUF(tp, &tp->t_mgt_login_resp_buf, 0, 0,
6227c478bd9Sstevel@tonic-gate 	    DDI_DMA_SYNC_FORKERNEL);
6237c478bd9Sstevel@tonic-gate 	bcopy(tp->t_mgt_login_resp_buf.bb_kaddr, &lp->l_login_resp,
6247c478bd9Sstevel@tonic-gate 	    sizeof (sbp2_login_resp_t));
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/* convert from BE to native endianness */
6277c478bd9Sstevel@tonic-gate 	SBP2_SWAP16_1(lp->l_login_resp.lr_len);
6287c478bd9Sstevel@tonic-gate 	SBP2_SWAP16_1(lp->l_login_resp.lr_login_id);
6297c478bd9Sstevel@tonic-gate 	SBP2_SWAP32_2(lp->l_login_resp.lr_cmd_agent);
6307c478bd9Sstevel@tonic-gate 	SBP2_SWAP16_1(lp->l_login_resp.lr_reconnect_hold);
6317c478bd9Sstevel@tonic-gate 	lp->l_login_resp.lr_reconnect_hold++;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	sp->s_agent_offset = SBP2_ADDR2UINT64(lp->l_login_resp.lr_cmd_agent);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	lp->l_logged_in = B_TRUE;
6367c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_release(tp);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_agent_init(&sp->s_agent, sp->s_agent_offset, tp)) !=
6417c478bd9Sstevel@tonic-gate 	    SBP2_SUCCESS) {
6427c478bd9Sstevel@tonic-gate 		sbp2_ses_fini(sp);
6437c478bd9Sstevel@tonic-gate 		lp->l_ses = NULL;
6447c478bd9Sstevel@tonic-gate 		return (ret);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	*spp = lp->l_ses;
6487c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6527c478bd9Sstevel@tonic-gate int
sbp2_lun_logout(sbp2_lun_t * lp,sbp2_ses_t ** sp,int * berr,boolean_t phys)6537c478bd9Sstevel@tonic-gate sbp2_lun_logout(sbp2_lun_t *lp, sbp2_ses_t **sp, int *berr, boolean_t phys)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	ASSERT(*sp == lp->l_ses);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
6607c478bd9Sstevel@tonic-gate 	if (lp->l_logged_in) {
6617c478bd9Sstevel@tonic-gate 		lp->l_logged_in = B_FALSE;
6627c478bd9Sstevel@tonic-gate 		/* do physical LOGOUT if requested */
6637c478bd9Sstevel@tonic-gate 		if (phys) {
6647c478bd9Sstevel@tonic-gate 			mutex_exit(&tp->t_mutex);
6657c478bd9Sstevel@tonic-gate 			sbp2_lun_logout_orb(lp, tp, berr);
6667c478bd9Sstevel@tonic-gate 			mutex_enter(&tp->t_mutex);
6677c478bd9Sstevel@tonic-gate 		}
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	sbp2_agent_fini(&lp->l_ses->s_agent);
6717c478bd9Sstevel@tonic-gate 	sbp2_ses_fini(lp->l_ses);
6727c478bd9Sstevel@tonic-gate 	lp->l_ses = NULL;
6737c478bd9Sstevel@tonic-gate 	*sp = NULL;
6747c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate  * Issue LOGOUT mgt orb and wait for response. We are not interested in
6817c478bd9Sstevel@tonic-gate  * the success at the time, since the device may be disconnected or hung,
6827c478bd9Sstevel@tonic-gate  * just trying to make the best effort.
6837c478bd9Sstevel@tonic-gate  */
6847c478bd9Sstevel@tonic-gate static void
sbp2_lun_logout_orb(sbp2_lun_t * lp,sbp2_tgt_t * tp,int * berr)6857c478bd9Sstevel@tonic-gate sbp2_lun_logout_orb(sbp2_lun_t *lp, sbp2_tgt_t *tp, int *berr)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	sbp2_logout_orb_t *lorb;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_acquire(tp);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/* prepare logout ORB */
6927c478bd9Sstevel@tonic-gate 	lorb = (sbp2_logout_orb_t *)tp->t_mgt_orb_buf.bb_kaddr;
6937c478bd9Sstevel@tonic-gate 	bzero(lorb, sizeof (sbp2_logout_orb_t));
6947c478bd9Sstevel@tonic-gate 	lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGOUT |
6957c478bd9Sstevel@tonic-gate 	    SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2);
6967c478bd9Sstevel@tonic-gate 	lorb->lo_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id);
6977c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(lorb->lo_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr,
6987c478bd9Sstevel@tonic-gate 	    0);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/* send request */
7017c478bd9Sstevel@tonic-gate 	(void) sbp2_tgt_mgt_request(tp, berr);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_release(tp);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate static boolean_t
sbp2_lun_accepting_tasks(sbp2_lun_t * lp)7077c478bd9Sstevel@tonic-gate sbp2_lun_accepting_tasks(sbp2_lun_t *lp)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
7107c478bd9Sstevel@tonic-gate 	boolean_t	ret;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
7137c478bd9Sstevel@tonic-gate 	ret = ((lp->l_ses != NULL) && lp->l_logged_in && !lp->l_reconnecting);
7147c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
7157c478bd9Sstevel@tonic-gate 	return (ret);
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate /*
7197c478bd9Sstevel@tonic-gate  *
7207c478bd9Sstevel@tonic-gate  * --- session routines
7217c478bd9Sstevel@tonic-gate  *
7227c478bd9Sstevel@tonic-gate  */
7237c478bd9Sstevel@tonic-gate static int
sbp2_ses_init(sbp2_ses_t ** spp,sbp2_lun_t * lp,void (* cb)(void *,sbp2_task_t *),void * cb_arg)7247c478bd9Sstevel@tonic-gate sbp2_ses_init(sbp2_ses_t **spp, sbp2_lun_t *lp,
7257c478bd9Sstevel@tonic-gate     void (*cb)(void *, sbp2_task_t *), void *cb_arg)
7267c478bd9Sstevel@tonic-gate {
7277c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
7287c478bd9Sstevel@tonic-gate 	sbp2_ses_t	*sp;
7297c478bd9Sstevel@tonic-gate 	int		ret;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	sp = kmem_zalloc(sizeof (sbp2_ses_t), KM_SLEEP);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	sp->s_tgt = tp;
7347c478bd9Sstevel@tonic-gate 	sp->s_lun = lp;
7357c478bd9Sstevel@tonic-gate 	sp->s_status_cb = cb;
7367c478bd9Sstevel@tonic-gate 	sp->s_status_cb_arg = cb_arg;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	mutex_init(&sp->s_mutex, NULL, MUTEX_DRIVER,
7397c478bd9Sstevel@tonic-gate 	    SBP2_GET_IBLOCK_COOKIE(tp));
7407c478bd9Sstevel@tonic-gate 	mutex_init(&sp->s_task_mutex, NULL, MUTEX_DRIVER,
7417c478bd9Sstevel@tonic-gate 	    SBP2_GET_IBLOCK_COOKIE(tp));
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	/*
7447c478bd9Sstevel@tonic-gate 	 * status FIFO for block requests
7457c478bd9Sstevel@tonic-gate 	 */
7467c478bd9Sstevel@tonic-gate 	sp->s_status_fifo_buf.bb_len = sizeof (sbp2_status_t);
7477c478bd9Sstevel@tonic-gate 	sp->s_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED;
7487c478bd9Sstevel@tonic-gate 	sp->s_status_fifo_buf.bb_wb_cb = sbp2_status_fifo_wb_cb;
7497c478bd9Sstevel@tonic-gate 	sp->s_status_fifo_buf.bb_sbp2_priv = sp;
7507c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_BUF(tp, &sp->s_status_fifo_buf)) !=
7517c478bd9Sstevel@tonic-gate 	    SBP2_SUCCESS) {
7527c478bd9Sstevel@tonic-gate 		sbp2_ses_fini(sp);
7537c478bd9Sstevel@tonic-gate 		return (ret);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	*spp = sp;
7577c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate static void
sbp2_ses_fini(sbp2_ses_t * sp)7627c478bd9Sstevel@tonic-gate sbp2_ses_fini(sbp2_ses_t *sp)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_lun->l_tgt;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (sp->s_status_fifo_buf.bb_hdl != NULL) {
7677c478bd9Sstevel@tonic-gate 		SBP2_FREE_BUF(tp, &sp->s_status_fifo_buf);
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	mutex_destroy(&sp->s_task_mutex);
7717c478bd9Sstevel@tonic-gate 	mutex_destroy(&sp->s_mutex);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (sbp2_ses_t));
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate int
sbp2_ses_reconnect(sbp2_ses_t * sp,int * berr,uint16_t nodeID)7777c478bd9Sstevel@tonic-gate sbp2_ses_reconnect(sbp2_ses_t *sp, int *berr, uint16_t nodeID)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
7807c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp = sp->s_lun;
7817c478bd9Sstevel@tonic-gate 	int		ret;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	/* prevent new tasks from being submitted */
7847c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
7857c478bd9Sstevel@tonic-gate 	lp->l_reconnecting = B_TRUE;
7867c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * From 10.5 Task management event matrix:
7907c478bd9Sstevel@tonic-gate 	 *	Immediately upon detection of a bus reset, all command
7917c478bd9Sstevel@tonic-gate 	 *	block fetch agents transition to the reset state and
7927c478bd9Sstevel@tonic-gate 	 *	their associated task sets are cleared without
7937c478bd9Sstevel@tonic-gate 	 *	the return of completion status.
7947c478bd9Sstevel@tonic-gate 	 *
7957c478bd9Sstevel@tonic-gate 	 * Reset pending tasks so we can retry them later.
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 	sbp2_ses_reset_pending_tasks(sp, nodeID);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	ret = sbp2_ses_reconnect_orb(sp, berr);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
8027c478bd9Sstevel@tonic-gate 	lp->l_reconnecting = B_FALSE;
8037c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	return (ret);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate  * Send reconnect ORB. If operation fails, set lp->l_logged_in = B_FALSE.
8107c478bd9Sstevel@tonic-gate  */
8117c478bd9Sstevel@tonic-gate static int
sbp2_ses_reconnect_orb(sbp2_ses_t * sp,int * berr)8127c478bd9Sstevel@tonic-gate sbp2_ses_reconnect_orb(sbp2_ses_t *sp, int *berr)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
8157c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp = sp->s_lun;
8167c478bd9Sstevel@tonic-gate 	sbp2_agent_t	*ap = &sp->s_agent;
8177c478bd9Sstevel@tonic-gate 	sbp2_reconnect_orb_t *rorb;
8187c478bd9Sstevel@tonic-gate 	int		ret;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_acquire(tp);
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	/* prepare login ORB */
8237c478bd9Sstevel@tonic-gate 	rorb = (sbp2_reconnect_orb_t *)tp->t_mgt_orb_buf.bb_kaddr;
8247c478bd9Sstevel@tonic-gate 	bzero(rorb, sizeof (sbp2_reconnect_orb_t));
8257c478bd9Sstevel@tonic-gate 	rorb->ro_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_RECONNECT |
8267c478bd9Sstevel@tonic-gate 	    SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2);
8277c478bd9Sstevel@tonic-gate 	rorb->ro_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id);
8287c478bd9Sstevel@tonic-gate 	SBP2_ADDR_SET(rorb->ro_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr,
8297c478bd9Sstevel@tonic-gate 	    0);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	/* send request */
8327c478bd9Sstevel@tonic-gate 	if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) {
8337c478bd9Sstevel@tonic-gate 		mutex_enter(&tp->t_mutex);
8347c478bd9Sstevel@tonic-gate 		lp->l_logged_in = B_FALSE;
8357c478bd9Sstevel@tonic-gate 		mutex_exit(&tp->t_mutex);
8367c478bd9Sstevel@tonic-gate 	} else {
8377c478bd9Sstevel@tonic-gate 		/* after successful reset fetch agent is in RESET state */
8387c478bd9Sstevel@tonic-gate 		mutex_enter(&ap->a_mutex);
8397c478bd9Sstevel@tonic-gate 		ap->a_state = SBP2_AGENT_STATE_RESET;
8407c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	sbp2_mgt_agent_release(tp);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	return (ret);
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate static sbp2_task_t *
sbp2_ses_orbp2task(sbp2_ses_t * sp,uint64_t orbp)8507c478bd9Sstevel@tonic-gate sbp2_ses_orbp2task(sbp2_ses_t *sp, uint64_t orbp)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
8557c478bd9Sstevel@tonic-gate 	for (task = sp->s_task_head; task != NULL; task = task->ts_next) {
8567c478bd9Sstevel@tonic-gate 		if (task->ts_buf->bb_baddr == orbp) {
8577c478bd9Sstevel@tonic-gate 			break;
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
8617c478bd9Sstevel@tonic-gate 	return (task);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate  * This is where tasks (command ORB's) are signalled to the target.
8667c478bd9Sstevel@tonic-gate  * 'task' argument is allowed to be NULL, in which case the task will be
8677c478bd9Sstevel@tonic-gate  * taken from the current task list.
8687c478bd9Sstevel@tonic-gate  *
8697c478bd9Sstevel@tonic-gate  * Tasks are signalled one at a time by writing into ORB_POINTER register.
8707c478bd9Sstevel@tonic-gate  * While SBP-2 allows dynamic task list updates and using DOORBELL register,
8717c478bd9Sstevel@tonic-gate  * some devices have bugs that prevent using this strategy: e.g. some LaCie
8727c478bd9Sstevel@tonic-gate  * HDD's can corrupt data. Data integrity is more important than performance.
8737c478bd9Sstevel@tonic-gate  */
8747c478bd9Sstevel@tonic-gate int
sbp2_ses_submit_task(sbp2_ses_t * sp,sbp2_task_t * new_task)8757c478bd9Sstevel@tonic-gate sbp2_ses_submit_task(sbp2_ses_t *sp, sbp2_task_t *new_task)
8767c478bd9Sstevel@tonic-gate {
8777c478bd9Sstevel@tonic-gate 	sbp2_agent_t	*ap = &sp->s_agent;
8787c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
8797c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task;		/* task actually being submitted */
8807c478bd9Sstevel@tonic-gate 	boolean_t	callback;
8817c478bd9Sstevel@tonic-gate 	timeout_id_t	timeout_id;
8827c478bd9Sstevel@tonic-gate 	int		ret;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	if (!sbp2_lun_accepting_tasks(sp->s_lun)) {
8857c478bd9Sstevel@tonic-gate 		return (SBP2_ENODEV);
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	sbp2_agent_acquire(ap);	/* serialize */
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	/* if task provided, append it to the list */
8937c478bd9Sstevel@tonic-gate 	if (new_task != NULL) {
8947c478bd9Sstevel@tonic-gate 		ASSERT(new_task->ts_state == SBP2_TASK_INIT);
8957c478bd9Sstevel@tonic-gate 		sbp2_ses_append_task(sp, new_task);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/* if there is already a task in flight, exit */
8997c478bd9Sstevel@tonic-gate 	if ((ap->a_active_task != NULL) &&
9007c478bd9Sstevel@tonic-gate 	    (ap->a_active_task->ts_state == SBP2_TASK_PEND)) {
9017c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
9027c478bd9Sstevel@tonic-gate 		sbp2_agent_release(ap);
9037c478bd9Sstevel@tonic-gate 		return (SBP2_SUCCESS);
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 
906*8c067cfdSAlan Perry 	/*
907*8c067cfdSAlan Perry 	 * cannot submit tasks from interrupt context,
908*8c067cfdSAlan Perry 	 * upper layer driver is responsible to call nudge
909*8c067cfdSAlan Perry 	 */
910*8c067cfdSAlan Perry 	if (servicing_interrupt()) {
911*8c067cfdSAlan Perry 		mutex_exit(&ap->a_mutex);
912*8c067cfdSAlan Perry 		sbp2_agent_release(ap);
913*8c067cfdSAlan Perry 		return (SBP2_ECONTEXT);
914*8c067cfdSAlan Perry 	}
915*8c067cfdSAlan Perry 
9167c478bd9Sstevel@tonic-gate 	/* no active task, grab the first one on the list in INIT state */
9177c478bd9Sstevel@tonic-gate 	ap->a_active_task = sbp2_ses_find_task_state(sp, SBP2_TASK_INIT);
9187c478bd9Sstevel@tonic-gate 	if (ap->a_active_task == NULL) {
9197c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
9207c478bd9Sstevel@tonic-gate 		sbp2_agent_release(ap);
9217c478bd9Sstevel@tonic-gate 		return (SBP2_SUCCESS);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 	task = ap->a_active_task;
9247c478bd9Sstevel@tonic-gate 	task->ts_ses = sp;
9257c478bd9Sstevel@tonic-gate 	task->ts_state = SBP2_TASK_PEND;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/* can't work with a dead agent */
9287c478bd9Sstevel@tonic-gate 	if (sbp2_agent_keepalive(ap, &task->ts_bus_error) != SBP2_SUCCESS) {
9297c478bd9Sstevel@tonic-gate 		task->ts_error = SBP2_TASK_ERR_DEAD;
9307c478bd9Sstevel@tonic-gate 		goto error;
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/*
9347c478bd9Sstevel@tonic-gate 	 * In theory, we should schedule task timeout after it's been submitted.
9357c478bd9Sstevel@tonic-gate 	 * However, some fast tasks complete even before timeout is scheduled.
9367c478bd9Sstevel@tonic-gate 	 * To avoid additional complications in the code, schedule timeout now.
9377c478bd9Sstevel@tonic-gate 	 */
9387c478bd9Sstevel@tonic-gate 	ASSERT(task->ts_timeout_id == 0);
9397c478bd9Sstevel@tonic-gate 	task->ts_time_start = gethrtime();
9407c478bd9Sstevel@tonic-gate 	if (task->ts_timeout > 0) {
9417c478bd9Sstevel@tonic-gate 		task->ts_timeout_id = timeout(sbp2_task_timeout, task,
9427c478bd9Sstevel@tonic-gate 		    task->ts_timeout * drv_usectohz(1000000));
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/* notify fetch agent */
9467c478bd9Sstevel@tonic-gate 	ap->a_state = SBP2_AGENT_STATE_ACTIVE;
9477c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
9487c478bd9Sstevel@tonic-gate 	ret = sbp2_agent_write_orbp(ap, task->ts_buf->bb_baddr,
9497c478bd9Sstevel@tonic-gate 	    &task->ts_bus_error);
9507c478bd9Sstevel@tonic-gate 	tp->t_stat.stat_submit_orbp++;
9517c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if (ret != SBP2_SUCCESS) {
9547c478bd9Sstevel@tonic-gate 		ap->a_state = SBP2_AGENT_STATE_DEAD;
9557c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_dead++;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		if (task->ts_timeout_id != 0) {
9587c478bd9Sstevel@tonic-gate 			timeout_id = task->ts_timeout_id;
9597c478bd9Sstevel@tonic-gate 			task->ts_timeout_id = 0;
9607c478bd9Sstevel@tonic-gate 			(void) untimeout(timeout_id);
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 		task->ts_error = SBP2_TASK_ERR_BUS;
9637c478bd9Sstevel@tonic-gate 		goto error;
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	sbp2_agent_release(ap);
9697c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate error:
9727c478bd9Sstevel@tonic-gate 	/*
9737c478bd9Sstevel@tonic-gate 	 * Return immediate error if failed task is the one being submitted,
9747c478bd9Sstevel@tonic-gate 	 * otherwise use callback.
9757c478bd9Sstevel@tonic-gate 	 */
9767c478bd9Sstevel@tonic-gate 	callback = (ap->a_active_task != new_task);
977f2b7ce3eSartem 	ASSERT(task == ap->a_active_task);
9787c478bd9Sstevel@tonic-gate 	ap->a_active_task = NULL;
9797c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
9807c478bd9Sstevel@tonic-gate 	sbp2_agent_release(ap);
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	/*
9837c478bd9Sstevel@tonic-gate 	 * Remove task from the list. It is important not to change task state
9847c478bd9Sstevel@tonic-gate 	 * to SBP2_TASK_COMP while it's still on the list, to avoid race with
9857c478bd9Sstevel@tonic-gate 	 * upper layer driver (e.g. scsa1394).
9867c478bd9Sstevel@tonic-gate 	 */
987f2b7ce3eSartem 	ret = sbp2_ses_remove_task(sp, task);
9887c478bd9Sstevel@tonic-gate 	ASSERT(ret == SBP2_SUCCESS);
989f2b7ce3eSartem 	task->ts_state = SBP2_TASK_COMP;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	if (callback) {
992f2b7ce3eSartem 		sp->s_status_cb(sp->s_status_cb_arg, task);
9937c478bd9Sstevel@tonic-gate 		return (SBP2_SUCCESS);
9947c478bd9Sstevel@tonic-gate 	} else {
9957c478bd9Sstevel@tonic-gate 		/* upper layer driver is responsible to call nudge */
9967c478bd9Sstevel@tonic-gate 		return (SBP2_FAILURE);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate void
sbp2_ses_nudge(sbp2_ses_t * sp)10017c478bd9Sstevel@tonic-gate sbp2_ses_nudge(sbp2_ses_t *sp)
10027c478bd9Sstevel@tonic-gate {
10037c478bd9Sstevel@tonic-gate 	(void) sbp2_ses_submit_task(sp, NULL);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate  * append task to the task list
10087c478bd9Sstevel@tonic-gate  */
10097c478bd9Sstevel@tonic-gate static void
sbp2_ses_append_task(sbp2_ses_t * sp,sbp2_task_t * task)10107c478bd9Sstevel@tonic-gate sbp2_ses_append_task(sbp2_ses_t *sp, sbp2_task_t *task)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
10157c478bd9Sstevel@tonic-gate 	if (sp->s_task_head == NULL) {
10167c478bd9Sstevel@tonic-gate 		ASSERT(sp->s_task_tail == NULL);
10177c478bd9Sstevel@tonic-gate 		ASSERT(sp->s_task_cnt == 0);
10187c478bd9Sstevel@tonic-gate 		task->ts_prev = task->ts_next = NULL;
10197c478bd9Sstevel@tonic-gate 		sp->s_task_head = sp->s_task_tail = task;
10207c478bd9Sstevel@tonic-gate 	} else {
10217c478bd9Sstevel@tonic-gate 		ASSERT(sp->s_task_cnt > 0);
10227c478bd9Sstevel@tonic-gate 		task->ts_next = NULL;
10237c478bd9Sstevel@tonic-gate 		task->ts_prev = sp->s_task_tail;
10247c478bd9Sstevel@tonic-gate 		sp->s_task_tail->ts_next = task;
10257c478bd9Sstevel@tonic-gate 		sp->s_task_tail = task;
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 	ASSERT(task != task->ts_prev);
10287c478bd9Sstevel@tonic-gate 	ASSERT(task != task->ts_next);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	sp->s_task_cnt++;
10317c478bd9Sstevel@tonic-gate 	if (sp->s_task_cnt > tp->t_stat.stat_task_max) {
10327c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_task_max = sp->s_task_cnt;
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate /*
10387c478bd9Sstevel@tonic-gate  * remove task from the task list
10397c478bd9Sstevel@tonic-gate  */
10407c478bd9Sstevel@tonic-gate static int
sbp2_ses_remove_task_locked(sbp2_ses_t * sp,sbp2_task_t * task)10417c478bd9Sstevel@tonic-gate sbp2_ses_remove_task_locked(sbp2_ses_t *sp, sbp2_task_t *task)
10427c478bd9Sstevel@tonic-gate {
10437c478bd9Sstevel@tonic-gate 	sp->s_task_cnt--;
10447c478bd9Sstevel@tonic-gate 	if (task == sp->s_task_head) {			/* first */
10457c478bd9Sstevel@tonic-gate 		ASSERT(task->ts_prev == NULL);
10467c478bd9Sstevel@tonic-gate 		if (task->ts_next == NULL) {		/*   and last */
10477c478bd9Sstevel@tonic-gate 			ASSERT(sp->s_task_cnt == 0);
10487c478bd9Sstevel@tonic-gate 			sp->s_task_head = sp->s_task_tail = NULL;
10497c478bd9Sstevel@tonic-gate 		} else {				/*   but not last */
10507c478bd9Sstevel@tonic-gate 			sp->s_task_head = task->ts_next;
10517c478bd9Sstevel@tonic-gate 			sp->s_task_head->ts_prev = NULL;
10527c478bd9Sstevel@tonic-gate 		}
10537c478bd9Sstevel@tonic-gate 	} else if (task == sp->s_task_tail) {		/* last but not first */
10547c478bd9Sstevel@tonic-gate 		ASSERT(task->ts_next == NULL);
10557c478bd9Sstevel@tonic-gate 		sp->s_task_tail = task->ts_prev;
10567c478bd9Sstevel@tonic-gate 		sp->s_task_tail->ts_next = NULL;
10577c478bd9Sstevel@tonic-gate 	} else {					/* in the middle */
10587c478bd9Sstevel@tonic-gate 		task->ts_prev->ts_next = task->ts_next;
10597c478bd9Sstevel@tonic-gate 		task->ts_next->ts_prev = task->ts_prev;
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 	task->ts_prev = task->ts_next = NULL;
10627c478bd9Sstevel@tonic-gate 	ASSERT(sp->s_task_cnt >= 0);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate int
sbp2_ses_remove_task(sbp2_ses_t * sp,sbp2_task_t * task)10687c478bd9Sstevel@tonic-gate sbp2_ses_remove_task(sbp2_ses_t *sp, sbp2_task_t *task)
10697c478bd9Sstevel@tonic-gate {
10707c478bd9Sstevel@tonic-gate 	int	ret;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
10737c478bd9Sstevel@tonic-gate 	ret = sbp2_ses_remove_task_locked(sp, task);
10747c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	return (ret);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  * Return first task on the list in specified state.
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate sbp2_task_t *
sbp2_ses_find_task_state(sbp2_ses_t * sp,sbp2_task_state_t state)10837c478bd9Sstevel@tonic-gate sbp2_ses_find_task_state(sbp2_ses_t *sp, sbp2_task_state_t state)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
10887c478bd9Sstevel@tonic-gate 	for (task = sp->s_task_head; task != NULL; task = task->ts_next) {
10897c478bd9Sstevel@tonic-gate 		if (task->ts_state == state) {
10907c478bd9Sstevel@tonic-gate 			break;
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 	}
10937c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	return (task);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate /*
10997c478bd9Sstevel@tonic-gate  * Remove first task on the list. Returns pointer to the removed task or NULL.
11007c478bd9Sstevel@tonic-gate  */
11017c478bd9Sstevel@tonic-gate sbp2_task_t *
sbp2_ses_remove_first_task(sbp2_ses_t * sp)11027c478bd9Sstevel@tonic-gate sbp2_ses_remove_first_task(sbp2_ses_t *sp)
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
11077c478bd9Sstevel@tonic-gate 	task = sp->s_task_head;
11087c478bd9Sstevel@tonic-gate 	if (task != NULL) {
11097c478bd9Sstevel@tonic-gate 		(void) sbp2_ses_remove_task_locked(sp, task);
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	return (task);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate  * Remove first task on the list only if it's in specified state.
11187c478bd9Sstevel@tonic-gate  * Returns pointer to the removed task or NULL.
11197c478bd9Sstevel@tonic-gate  */
11207c478bd9Sstevel@tonic-gate sbp2_task_t *
sbp2_ses_remove_first_task_state(sbp2_ses_t * sp,sbp2_task_state_t state)11217c478bd9Sstevel@tonic-gate sbp2_ses_remove_first_task_state(sbp2_ses_t *sp, sbp2_task_state_t state)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
11267c478bd9Sstevel@tonic-gate 	if ((sp->s_task_head != NULL) && (sp->s_task_head->ts_state == state)) {
11277c478bd9Sstevel@tonic-gate 		task = sp->s_task_head;
11287c478bd9Sstevel@tonic-gate 		(void) sbp2_ses_remove_task_locked(sp, task);
11297c478bd9Sstevel@tonic-gate 	}
11307c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	return (task);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate /*
11367c478bd9Sstevel@tonic-gate  * Remove first task on the list. If there's timeout, untimeout it.
11377c478bd9Sstevel@tonic-gate  * Returns pointer to the removed task or NULL.
11387c478bd9Sstevel@tonic-gate  */
11397c478bd9Sstevel@tonic-gate sbp2_task_t *
sbp2_ses_cancel_first_task(sbp2_ses_t * sp)11407c478bd9Sstevel@tonic-gate sbp2_ses_cancel_first_task(sbp2_ses_t *sp)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
11437c478bd9Sstevel@tonic-gate 	timeout_id_t	timeout_id;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
11467c478bd9Sstevel@tonic-gate 	task = sp->s_task_head;
11477c478bd9Sstevel@tonic-gate 	if (task != NULL) {
11487c478bd9Sstevel@tonic-gate 		(void) sbp2_ses_remove_task_locked(sp, task);
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	if ((task != NULL) && ((timeout_id = task->ts_timeout_id) != 0)) {
11537c478bd9Sstevel@tonic-gate 		task->ts_timeout_id = 0;
11547c478bd9Sstevel@tonic-gate 		(void) untimeout(timeout_id);
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	return (task);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate  * Reset pending tasks on the list to their initial state.
11627c478bd9Sstevel@tonic-gate  */
11637c478bd9Sstevel@tonic-gate static void
sbp2_ses_reset_pending_tasks(sbp2_ses_t * sp,uint16_t nodeID)11647c478bd9Sstevel@tonic-gate sbp2_ses_reset_pending_tasks(sbp2_ses_t *sp, uint16_t nodeID)
11657c478bd9Sstevel@tonic-gate {
11667c478bd9Sstevel@tonic-gate 	sbp2_agent_t	*ap = &sp->s_agent;
11677c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = NULL;
11687c478bd9Sstevel@tonic-gate 	timeout_id_t	timeout_id;
11697c478bd9Sstevel@tonic-gate 	sbp2_cmd_orb_t	*orb;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_task_mutex);
11727c478bd9Sstevel@tonic-gate 	for (task = sp->s_task_head; task != NULL; task = task->ts_next) {
11737c478bd9Sstevel@tonic-gate 		task->ts_state = SBP2_TASK_INIT;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 		/* cancel timeout */
11767c478bd9Sstevel@tonic-gate 		if ((timeout_id = task->ts_timeout_id) != 0) {
11777c478bd9Sstevel@tonic-gate 			task->ts_timeout_id = 0;
11787c478bd9Sstevel@tonic-gate 			(void) untimeout(timeout_id);
11797c478bd9Sstevel@tonic-gate 		}
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		/* update ORB nodeID */
11827c478bd9Sstevel@tonic-gate 		orb = (sbp2_cmd_orb_t *)sbp2_task_orb_kaddr(task);
11837c478bd9Sstevel@tonic-gate 		*(uint16_t *)orb->co_data_descr = SBP2_SWAP16(nodeID);
11847c478bd9Sstevel@tonic-gate 		sbp2_task_orb_sync(sp->s_lun, task, DDI_DMA_SYNC_FORDEV);
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_task_mutex);
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
11897c478bd9Sstevel@tonic-gate 	ap->a_active_task = NULL;
11907c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate int
sbp2_ses_agent_reset(sbp2_ses_t * sp,int * berr)11947c478bd9Sstevel@tonic-gate sbp2_ses_agent_reset(sbp2_ses_t *sp, int *berr)
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	return (sbp2_agent_reset(&sp->s_agent, berr));
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate int
sbp2_ses_abort_task(sbp2_ses_t * sp,sbp2_task_t * task,int * berr)12007c478bd9Sstevel@tonic-gate sbp2_ses_abort_task(sbp2_ses_t *sp, sbp2_task_t *task, int *berr)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
12037c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp = sp->s_lun;
12047c478bd9Sstevel@tonic-gate 	uint16_t	params;
12057c478bd9Sstevel@tonic-gate 	sbp2_cmd_orb_t	*orb = (sbp2_cmd_orb_t *)task->ts_buf->bb_kaddr;
12067c478bd9Sstevel@tonic-gate 	int		ret = SBP2_SUCCESS;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	/* mark ORB as dummy ORB */
12097c478bd9Sstevel@tonic-gate 	params = (orb->co_params & ~SBP2_ORB_RQ_FMT) | SBP2_ORB_RQ_FMT_DUMMY;
12107c478bd9Sstevel@tonic-gate 	orb->co_params = params;
12117c478bd9Sstevel@tonic-gate 	(void) SBP2_SYNC_BUF(tp, task->ts_buf, 0, 0, DDI_DMA_SYNC_FORDEV);
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id,
12147c478bd9Sstevel@tonic-gate 	    SBP2_ORB_MGT_FUNC_ABORT_TASK, task->ts_buf->bb_baddr, berr);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	return (ret);
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate int
sbp2_ses_abort_task_set(sbp2_ses_t * sp,int * berr)12217c478bd9Sstevel@tonic-gate sbp2_ses_abort_task_set(sbp2_ses_t *sp, int *berr)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
12247c478bd9Sstevel@tonic-gate 	sbp2_lun_t	*lp = sp->s_lun;
12257c478bd9Sstevel@tonic-gate 	int		ret;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id,
12287c478bd9Sstevel@tonic-gate 	    SBP2_ORB_MGT_FUNC_ABORT_TASK_SET, 0, berr);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	return (ret);
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate /*
12357c478bd9Sstevel@tonic-gate  *
12367c478bd9Sstevel@tonic-gate  * ORB functions
12377c478bd9Sstevel@tonic-gate  *
12387c478bd9Sstevel@tonic-gate  * allocate ORB resources
12397c478bd9Sstevel@tonic-gate  *
12407c478bd9Sstevel@tonic-gate  * we maintain a freelist of ORB's for faster allocation
12417c478bd9Sstevel@tonic-gate  */
12427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12437c478bd9Sstevel@tonic-gate static sbp2_bus_buf_t *
sbp2_orb_freelist_get(sbp2_lun_t * lp,sbp2_task_t * task,int len)12447c478bd9Sstevel@tonic-gate sbp2_orb_freelist_get(sbp2_lun_t *lp, sbp2_task_t *task, int len)
12457c478bd9Sstevel@tonic-gate {
12467c478bd9Sstevel@tonic-gate 	sbp2_buf_list_t	*bl = &lp->l_orb_freelist;
12477c478bd9Sstevel@tonic-gate 	sbp2_bus_buf_t	*buf = NULL;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	mutex_enter(&bl->bl_mutex);
12507c478bd9Sstevel@tonic-gate 	if ((bl->bl_head != NULL) && (bl->bl_head->bb_len == len)) {
12517c478bd9Sstevel@tonic-gate 		buf = bl->bl_head;
12527c478bd9Sstevel@tonic-gate 		bl->bl_head = buf->bb_next;
12537c478bd9Sstevel@tonic-gate 		if (bl->bl_tail == buf) {	/* last one? */
12547c478bd9Sstevel@tonic-gate 			ASSERT(bl->bl_head == NULL);
12557c478bd9Sstevel@tonic-gate 			bl->bl_tail = NULL;
12567c478bd9Sstevel@tonic-gate 		}
12577c478bd9Sstevel@tonic-gate 		bl->bl_len--;
12587c478bd9Sstevel@tonic-gate 		buf->bb_next = NULL;
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 	mutex_exit(&bl->bl_mutex);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	return (buf);
12637c478bd9Sstevel@tonic-gate }
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate static int
sbp2_orb_freelist_put(sbp2_lun_t * lp,sbp2_bus_buf_t * buf)12667c478bd9Sstevel@tonic-gate sbp2_orb_freelist_put(sbp2_lun_t *lp, sbp2_bus_buf_t *buf)
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate 	sbp2_buf_list_t	*bl = &lp->l_orb_freelist;
12697c478bd9Sstevel@tonic-gate 	int		ret;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	mutex_enter(&bl->bl_mutex);
12727c478bd9Sstevel@tonic-gate 	if (bl->bl_len < SBP2_ORB_FREELIST_MAX) {
12737c478bd9Sstevel@tonic-gate 		if (bl->bl_head == NULL) {
12747c478bd9Sstevel@tonic-gate 			ASSERT(bl->bl_tail == NULL);
12757c478bd9Sstevel@tonic-gate 			bl->bl_head = bl->bl_tail = buf;
12767c478bd9Sstevel@tonic-gate 		} else {
12777c478bd9Sstevel@tonic-gate 			bl->bl_tail->bb_next = buf;
12787c478bd9Sstevel@tonic-gate 			bl->bl_tail = buf;
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 		buf->bb_next = NULL;
12817c478bd9Sstevel@tonic-gate 		bl->bl_len++;
12827c478bd9Sstevel@tonic-gate 		ret = SBP2_SUCCESS;
12837c478bd9Sstevel@tonic-gate 	} else {
12847c478bd9Sstevel@tonic-gate 		ret = SBP2_FAILURE;
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 	mutex_exit(&bl->bl_mutex);
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	return (ret);
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate static void
sbp2_orb_freelist_destroy(sbp2_lun_t * lp)12927c478bd9Sstevel@tonic-gate sbp2_orb_freelist_destroy(sbp2_lun_t *lp)
12937c478bd9Sstevel@tonic-gate {
12947c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
12957c478bd9Sstevel@tonic-gate 	sbp2_buf_list_t	*bl = &lp->l_orb_freelist;
12967c478bd9Sstevel@tonic-gate 	sbp2_bus_buf_t	*buf, *buf_next;
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	mutex_enter(&bl->bl_mutex);
12997c478bd9Sstevel@tonic-gate 	for (buf = bl->bl_head; buf != NULL; ) {
13007c478bd9Sstevel@tonic-gate 		SBP2_FREE_BUF(tp, buf);
13017c478bd9Sstevel@tonic-gate 		buf_next = buf->bb_next;
13027c478bd9Sstevel@tonic-gate 		kmem_free(buf, sizeof (sbp2_bus_buf_t));
13037c478bd9Sstevel@tonic-gate 		buf = buf_next;
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 	bl->bl_head = bl->bl_tail = NULL;
13067c478bd9Sstevel@tonic-gate 	mutex_exit(&bl->bl_mutex);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate int
sbp2_task_orb_alloc(sbp2_lun_t * lp,sbp2_task_t * task,int len)13107c478bd9Sstevel@tonic-gate sbp2_task_orb_alloc(sbp2_lun_t *lp, sbp2_task_t *task, int len)
13117c478bd9Sstevel@tonic-gate {
13127c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
13137c478bd9Sstevel@tonic-gate 	int		buf_len;
13147c478bd9Sstevel@tonic-gate 	int		ret;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	buf_len = SBP2_ORB_SIZE_ROUNDUP(tp, len);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	/* try freelist first */
13197c478bd9Sstevel@tonic-gate 	if ((task->ts_buf = sbp2_orb_freelist_get(lp, task, buf_len)) != NULL) {
13207c478bd9Sstevel@tonic-gate 		return (SBP2_SUCCESS);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	/* if no free buffers, allocate new */
13247c478bd9Sstevel@tonic-gate 	task->ts_buf = kmem_zalloc(sizeof (sbp2_bus_buf_t), KM_SLEEP);
13257c478bd9Sstevel@tonic-gate 	task->ts_buf->bb_len = buf_len;
13267c478bd9Sstevel@tonic-gate 	task->ts_buf->bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD;
13277c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_BUF(tp, task->ts_buf)) != SBP2_SUCCESS) {
13287c478bd9Sstevel@tonic-gate 		kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t));
13297c478bd9Sstevel@tonic-gate 		task->ts_buf = NULL;
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	return (ret);
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate void
sbp2_task_orb_free(sbp2_lun_t * lp,sbp2_task_t * task)13367c478bd9Sstevel@tonic-gate sbp2_task_orb_free(sbp2_lun_t *lp, sbp2_task_t *task)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = lp->l_tgt;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (task->ts_buf != NULL) {
13417c478bd9Sstevel@tonic-gate 		if (sbp2_orb_freelist_put(lp, task->ts_buf) != SBP2_SUCCESS) {
13427c478bd9Sstevel@tonic-gate 			SBP2_FREE_BUF(tp, task->ts_buf);
13437c478bd9Sstevel@tonic-gate 			kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t));
13447c478bd9Sstevel@tonic-gate 		}
13457c478bd9Sstevel@tonic-gate 		task->ts_buf = NULL;
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate void *
sbp2_task_orb_kaddr(sbp2_task_t * task)13507c478bd9Sstevel@tonic-gate sbp2_task_orb_kaddr(sbp2_task_t *task)
13517c478bd9Sstevel@tonic-gate {
13527c478bd9Sstevel@tonic-gate 	return (task->ts_buf->bb_kaddr);
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate void
sbp2_task_orb_sync(sbp2_lun_t * lp,sbp2_task_t * task,int flags)13567c478bd9Sstevel@tonic-gate sbp2_task_orb_sync(sbp2_lun_t *lp, sbp2_task_t *task, int flags)
13577c478bd9Sstevel@tonic-gate {
13587c478bd9Sstevel@tonic-gate 	(void) SBP2_SYNC_BUF(lp->l_tgt, task->ts_buf, 0, 0, flags);
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate /*
13627c478bd9Sstevel@tonic-gate  *
13637c478bd9Sstevel@tonic-gate  * --- fetch agent routines
13647c478bd9Sstevel@tonic-gate  *
13657c478bd9Sstevel@tonic-gate  */
13667c478bd9Sstevel@tonic-gate static int
sbp2_agent_init(sbp2_agent_t * ap,uint64_t offset,sbp2_tgt_t * tp)13677c478bd9Sstevel@tonic-gate sbp2_agent_init(sbp2_agent_t *ap, uint64_t offset, sbp2_tgt_t *tp)
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate 	int	ret;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	/* paranoia */
13727c478bd9Sstevel@tonic-gate 	if (offset == 0) {
13737c478bd9Sstevel@tonic-gate 		return (SBP2_FAILURE);
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	ap->a_tgt = tp;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	ap->a_reg_agent_state = offset + SBP2_AGENT_STATE_OFFSET;
13797c478bd9Sstevel@tonic-gate 	ap->a_reg_agent_reset = offset + SBP2_AGENT_RESET_OFFSET;
13807c478bd9Sstevel@tonic-gate 	ap->a_reg_orbp = offset + SBP2_ORB_POINTER_OFFSET;
13817c478bd9Sstevel@tonic-gate 	ap->a_reg_doorbell = offset + SBP2_DOORBELL_OFFSET;
13827c478bd9Sstevel@tonic-gate 	ap->a_reg_unsol_status_enable = offset +
13837c478bd9Sstevel@tonic-gate 	    SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	/*
13867c478bd9Sstevel@tonic-gate 	 * allocate bus commands
13877c478bd9Sstevel@tonic-gate 	 */
13887c478bd9Sstevel@tonic-gate 	if ((ret = SBP2_ALLOC_CMD(tp, &ap->a_cmd, 0)) != SBP2_SUCCESS) {
13897c478bd9Sstevel@tonic-gate 		return (ret);
13907c478bd9Sstevel@tonic-gate 	}
13917c478bd9Sstevel@tonic-gate 	ap->a_cmd_data = allocb(sizeof (sbp2_orbp_t), BPRI_HI);
13927c478bd9Sstevel@tonic-gate 	if (ap->a_cmd_data == NULL) {
13937c478bd9Sstevel@tonic-gate 		sbp2_agent_fini(ap);
13947c478bd9Sstevel@tonic-gate 		return (SBP2_ENOMEM);
13957c478bd9Sstevel@tonic-gate 	}
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	mutex_init(&ap->a_mutex, NULL, MUTEX_DRIVER,
13987c478bd9Sstevel@tonic-gate 	    SBP2_GET_IBLOCK_COOKIE(tp));
13997c478bd9Sstevel@tonic-gate 	cv_init(&ap->a_cv, NULL, CV_DRIVER, NULL);
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate #ifndef __lock_lint
14027c478bd9Sstevel@tonic-gate 	ap->a_state = SBP2_AGENT_STATE_RESET;
14037c478bd9Sstevel@tonic-gate #endif
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	return (SBP2_SUCCESS);
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate static void
sbp2_agent_fini(sbp2_agent_t * ap)14107c478bd9Sstevel@tonic-gate sbp2_agent_fini(sbp2_agent_t *ap)
14117c478bd9Sstevel@tonic-gate {
14127c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = ap->a_tgt;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	/* free bus commands */
14157c478bd9Sstevel@tonic-gate 	if (ap->a_cmd != NULL) {
14167c478bd9Sstevel@tonic-gate 		SBP2_FREE_CMD(tp, ap->a_cmd);
14177c478bd9Sstevel@tonic-gate 	}
14187c478bd9Sstevel@tonic-gate 	if (ap->a_cmd_data != NULL) {
14197c478bd9Sstevel@tonic-gate 		freeb(ap->a_cmd_data);
14207c478bd9Sstevel@tonic-gate 	}
14217c478bd9Sstevel@tonic-gate 	cv_destroy(&ap->a_cv);
14227c478bd9Sstevel@tonic-gate 	mutex_destroy(&ap->a_mutex);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate static void
sbp2_agent_acquire_locked(sbp2_agent_t * ap)14277c478bd9Sstevel@tonic-gate sbp2_agent_acquire_locked(sbp2_agent_t *ap)
14287c478bd9Sstevel@tonic-gate {
14297c478bd9Sstevel@tonic-gate 	while (ap->a_acquired) {
14307c478bd9Sstevel@tonic-gate 		cv_wait(&ap->a_cv, &ap->a_mutex);
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 	ap->a_acquired = B_TRUE;
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate static void
sbp2_agent_release_locked(sbp2_agent_t * ap)14377c478bd9Sstevel@tonic-gate sbp2_agent_release_locked(sbp2_agent_t *ap)
14387c478bd9Sstevel@tonic-gate {
14397c478bd9Sstevel@tonic-gate 	ap->a_acquired = B_FALSE;
14407c478bd9Sstevel@tonic-gate 	cv_signal(&ap->a_cv);		/* wake next waiter */
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate static void
sbp2_agent_acquire(sbp2_agent_t * ap)14457c478bd9Sstevel@tonic-gate sbp2_agent_acquire(sbp2_agent_t *ap)
14467c478bd9Sstevel@tonic-gate {
14477c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
14487c478bd9Sstevel@tonic-gate 	sbp2_agent_acquire_locked(ap);
14497c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate static void
sbp2_agent_release(sbp2_agent_t * ap)14547c478bd9Sstevel@tonic-gate sbp2_agent_release(sbp2_agent_t *ap)
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
14577c478bd9Sstevel@tonic-gate 	sbp2_agent_release_locked(ap);
14587c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate static int
sbp2_agent_keepalive(sbp2_agent_t * ap,int * berr)14637c478bd9Sstevel@tonic-gate sbp2_agent_keepalive(sbp2_agent_t *ap, int *berr)
14647c478bd9Sstevel@tonic-gate {
14657c478bd9Sstevel@tonic-gate 	boolean_t	acquired;
14667c478bd9Sstevel@tonic-gate 	int		ret = SBP2_SUCCESS;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ap->a_mutex));
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	if (ap->a_state == SBP2_AGENT_STATE_DEAD) {
14717c478bd9Sstevel@tonic-gate 		acquired = ap->a_acquired;
14727c478bd9Sstevel@tonic-gate 		if (!acquired) {
14737c478bd9Sstevel@tonic-gate 			sbp2_agent_acquire_locked(ap);
14747c478bd9Sstevel@tonic-gate 		}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
14777c478bd9Sstevel@tonic-gate 		ret = sbp2_agent_reset(ap, berr);
14787c478bd9Sstevel@tonic-gate 		mutex_enter(&ap->a_mutex);
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 		if (!acquired) {
14817c478bd9Sstevel@tonic-gate 			sbp2_agent_release_locked(ap);
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 	}
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	return (ret);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate #ifndef __lock_lint
14897c478bd9Sstevel@tonic-gate static int
sbp2_agent_doorbell(sbp2_agent_t * ap,int * berr)14907c478bd9Sstevel@tonic-gate sbp2_agent_doorbell(sbp2_agent_t *ap, int *berr)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	return (SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_doorbell, 0, berr));
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate #endif
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate /*
14977c478bd9Sstevel@tonic-gate  * write into ORB_POINTER register and make sure it reached target
14987c478bd9Sstevel@tonic-gate  *
14997c478bd9Sstevel@tonic-gate  * From E.2: "If no acknowledgement is received by the initiator after a write
15007c478bd9Sstevel@tonic-gate  * 	to the ORB_POINTER register, the initiator should not retry the write.
15017c478bd9Sstevel@tonic-gate  *	The recommended method for error recovery is a write to the AGENT_RESET
15027c478bd9Sstevel@tonic-gate  *	register." So we can retry, but not in case of timeout.
15037c478bd9Sstevel@tonic-gate  */
15047c478bd9Sstevel@tonic-gate static int
sbp2_agent_write_orbp(sbp2_agent_t * ap,uint64_t baddr,int * berr)15057c478bd9Sstevel@tonic-gate sbp2_agent_write_orbp(sbp2_agent_t *ap, uint64_t baddr, int *berr)
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate 	int		i = 0;
15087c478bd9Sstevel@tonic-gate 	int		ret;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	SBP2_ORBP_SET(ap->a_cmd_data->b_rptr, baddr);
15117c478bd9Sstevel@tonic-gate 	ap->a_cmd_data->b_wptr = ap->a_cmd_data->b_rptr + 8;
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	for (;;) {
15147c478bd9Sstevel@tonic-gate 		ap->a_tgt->t_stat.stat_agent_worbp++;
15157c478bd9Sstevel@tonic-gate 		if ((ret = SBP2_WB(ap->a_tgt, ap->a_cmd, ap->a_reg_orbp,
15167c478bd9Sstevel@tonic-gate 		    ap->a_cmd_data, 8, berr)) == SBP2_SUCCESS) {
15177c478bd9Sstevel@tonic-gate 			return (ret);
15187c478bd9Sstevel@tonic-gate 		}
15197c478bd9Sstevel@tonic-gate 		ap->a_tgt->t_stat.stat_agent_worbp_fail++;
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 		if ((ret == SBP2_ETIMEOUT) ||
15227c478bd9Sstevel@tonic-gate 		    (++i > sbp2_write_orbp_nretries)) {
15237c478bd9Sstevel@tonic-gate 			break;
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 		if (sbp2_write_orbp_delay > 0) {
15267c478bd9Sstevel@tonic-gate 			drv_usecwait(sbp2_write_orbp_delay);
15277c478bd9Sstevel@tonic-gate 		}
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	return (ret);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate /*
15357c478bd9Sstevel@tonic-gate  * reset fetch agent by writing into AGENT_RESET register
15367c478bd9Sstevel@tonic-gate  */
15377c478bd9Sstevel@tonic-gate static int
sbp2_agent_reset(sbp2_agent_t * ap,int * berr)15387c478bd9Sstevel@tonic-gate sbp2_agent_reset(sbp2_agent_t *ap, int *berr)
15397c478bd9Sstevel@tonic-gate {
15407c478bd9Sstevel@tonic-gate 	int	i = 0;
15417c478bd9Sstevel@tonic-gate 	int	ret;
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	for (;;) {
15447c478bd9Sstevel@tonic-gate 		ap->a_tgt->t_stat.stat_agent_wreset++;
15457c478bd9Sstevel@tonic-gate 		if ((ret = SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_agent_reset,
15467c478bd9Sstevel@tonic-gate 		    0, berr)) == SBP2_SUCCESS) {
15477c478bd9Sstevel@tonic-gate 			mutex_enter(&ap->a_mutex);
15487c478bd9Sstevel@tonic-gate 			ap->a_state = SBP2_AGENT_STATE_RESET;
15497c478bd9Sstevel@tonic-gate 			mutex_exit(&ap->a_mutex);
15507c478bd9Sstevel@tonic-gate 			break;
15517c478bd9Sstevel@tonic-gate 		}
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 		ap->a_tgt->t_stat.stat_agent_wreset_fail++;
15547c478bd9Sstevel@tonic-gate 		if (++i > sbp2_submit_reset_nretries) {
15557c478bd9Sstevel@tonic-gate 			break;
15567c478bd9Sstevel@tonic-gate 		}
15577c478bd9Sstevel@tonic-gate 		if (sbp2_submit_reset_delay > 0) {
15587c478bd9Sstevel@tonic-gate 			drv_usecwait(sbp2_submit_reset_delay);
15597c478bd9Sstevel@tonic-gate 		}
15607c478bd9Sstevel@tonic-gate 	}
15617c478bd9Sstevel@tonic-gate 	return (ret);
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate /*
15657c478bd9Sstevel@tonic-gate  *
15667c478bd9Sstevel@tonic-gate  * --- callbacks and timeouts
15677c478bd9Sstevel@tonic-gate  *
15687c478bd9Sstevel@tonic-gate  */
15697c478bd9Sstevel@tonic-gate /*
15707c478bd9Sstevel@tonic-gate  * Status FIFO callback for mgt ORB's.
15717c478bd9Sstevel@tonic-gate  */
15727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15737c478bd9Sstevel@tonic-gate static void
sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t * buf,void * reqh,mblk_t ** bpp)15747c478bd9Sstevel@tonic-gate sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp)
15757c478bd9Sstevel@tonic-gate {
15767c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = buf->bb_sbp2_priv;
15777c478bd9Sstevel@tonic-gate 	int		len;
15787c478bd9Sstevel@tonic-gate 	sbp2_status_t	*st;
15797c478bd9Sstevel@tonic-gate 	uint64_t	orbp;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	len = MBLKL(*bpp);
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	/* 8 bytes minimum */
15847c478bd9Sstevel@tonic-gate 	if (len < 8) {
15857c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH);
15867c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_short++;
15877c478bd9Sstevel@tonic-gate 		return;
15887c478bd9Sstevel@tonic-gate 	}
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	/* convert 2-quadlet header from BE to native endianness */
15917c478bd9Sstevel@tonic-gate 	st = (sbp2_status_t *)(*bpp)->b_rptr;
15927c478bd9Sstevel@tonic-gate 	SBP2_SWAP16_1(st->st_orb_offset_hi);
15937c478bd9Sstevel@tonic-gate 	SBP2_SWAP32_1(st->st_orb_offset_lo);
15947c478bd9Sstevel@tonic-gate 	orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo;
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	if (orbp != tp->t_mgt_orb_buf.bb_baddr) {
15977c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE);
15987c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_mgt_notask++;
15997c478bd9Sstevel@tonic-gate 		return;
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	/* make a local copy of status block */
16037c478bd9Sstevel@tonic-gate 	bzero(&tp->t_mgt_status, sizeof (sbp2_status_t));
16047c478bd9Sstevel@tonic-gate 	bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	/* wake up waiter */
16097c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
16107c478bd9Sstevel@tonic-gate 	tp->t_mgt_status_rcvd = B_TRUE;
16117c478bd9Sstevel@tonic-gate 	cv_signal(&tp->t_mgt_status_cv);
16127c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate static void
sbp2_task_timeout(void * arg)16167c478bd9Sstevel@tonic-gate sbp2_task_timeout(void *arg)
16177c478bd9Sstevel@tonic-gate {
16187c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task = arg;
16197c478bd9Sstevel@tonic-gate 	sbp2_ses_t	*sp = task->ts_ses;
16207c478bd9Sstevel@tonic-gate 	sbp2_agent_t	*ap = &sp->s_agent;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	/* cancelled? */
16257c478bd9Sstevel@tonic-gate 	if (task->ts_timeout_id == 0) {
16267c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
16277c478bd9Sstevel@tonic-gate 		return;
16287c478bd9Sstevel@tonic-gate 	}
16297c478bd9Sstevel@tonic-gate 	task->ts_timeout_id = 0;
16307c478bd9Sstevel@tonic-gate 	task->ts_time_comp = gethrtime();
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	/* avoid race with other callbacks */
16337c478bd9Sstevel@tonic-gate 	if (task->ts_state != SBP2_TASK_PEND) {
16347c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
16357c478bd9Sstevel@tonic-gate 		return;
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	if (task == ap->a_active_task) {
16397c478bd9Sstevel@tonic-gate 		ap->a_active_task = NULL;
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 	task->ts_error = SBP2_TASK_ERR_TIMEOUT;
16427c478bd9Sstevel@tonic-gate 	task->ts_state = SBP2_TASK_COMP;
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	/* we mark agent DEAD so it's reset before next task is submitted */
16457c478bd9Sstevel@tonic-gate 	ap->a_state = SBP2_AGENT_STATE_DEAD;
16467c478bd9Sstevel@tonic-gate 	sp->s_tgt->t_stat.stat_status_dead++;
16477c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	sp->s_status_cb(sp->s_status_cb_arg, task);
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate /*
16537c478bd9Sstevel@tonic-gate  * Status FIFO callback for command ORB's. Also used for login ORB.
16547c478bd9Sstevel@tonic-gate  */
16557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16567c478bd9Sstevel@tonic-gate static void
sbp2_status_fifo_wb_cb(sbp2_bus_buf_t * buf,void * reqh,mblk_t ** bpp)16577c478bd9Sstevel@tonic-gate sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp)
16587c478bd9Sstevel@tonic-gate {
16597c478bd9Sstevel@tonic-gate 	sbp2_ses_t	*sp = buf->bb_sbp2_priv;
16607c478bd9Sstevel@tonic-gate 	sbp2_tgt_t	*tp = sp->s_tgt;
16617c478bd9Sstevel@tonic-gate 	sbp2_agent_t	*ap = &sp->s_agent;
16627c478bd9Sstevel@tonic-gate 	int		len;
16637c478bd9Sstevel@tonic-gate 	sbp2_status_t	*st;
16647c478bd9Sstevel@tonic-gate 	uint8_t		src;
16657c478bd9Sstevel@tonic-gate 	uint64_t	orbp;
16667c478bd9Sstevel@tonic-gate 	sbp2_task_t	*task;
16677c478bd9Sstevel@tonic-gate 	timeout_id_t	timeout_id;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	len = MBLKL(*bpp);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	/* 8 bytes minimum */
16727c478bd9Sstevel@tonic-gate 	if (len < 8) {
16737c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH);
16747c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_short++;
16757c478bd9Sstevel@tonic-gate 		return;
16767c478bd9Sstevel@tonic-gate 	}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	/* convert 2-quadlet header from BE32 to native endianness */
16797c478bd9Sstevel@tonic-gate 	st = (sbp2_status_t *)(*bpp)->b_rptr;
16807c478bd9Sstevel@tonic-gate 	SBP2_SWAP16_1(st->st_orb_offset_hi);
16817c478bd9Sstevel@tonic-gate 	SBP2_SWAP32_1(st->st_orb_offset_lo);
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo;
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	/* login ORB status? */
16867c478bd9Sstevel@tonic-gate 	if (orbp == tp->t_mgt_orb_buf.bb_baddr) {
16877c478bd9Sstevel@tonic-gate 		bzero(&tp->t_mgt_status, sizeof (sbp2_status_t));
16887c478bd9Sstevel@tonic-gate 		bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len);
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 		/* wake up waiter */
16937c478bd9Sstevel@tonic-gate 		mutex_enter(&tp->t_mutex);
16947c478bd9Sstevel@tonic-gate 		tp->t_mgt_status_rcvd = B_TRUE;
16957c478bd9Sstevel@tonic-gate 		cv_signal(&tp->t_mgt_status_cv);
16967c478bd9Sstevel@tonic-gate 		mutex_exit(&tp->t_mutex);
16977c478bd9Sstevel@tonic-gate 		return;
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	/* dismiss unsolicited status */
17017c478bd9Sstevel@tonic-gate 	src = st->st_param & SBP2_ST_SRC;
17027c478bd9Sstevel@tonic-gate 	if (src == SBP2_ST_SRC_UNSOLICITED) {
17037c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE);
17047c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_unsolicited++;
17057c478bd9Sstevel@tonic-gate 		return;
17067c478bd9Sstevel@tonic-gate 	}
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	/* find task corresponding to this ORB pointer */
17097c478bd9Sstevel@tonic-gate 	if ((task = sbp2_ses_orbp2task(sp, orbp)) == NULL) {
17107c478bd9Sstevel@tonic-gate 		SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE);
17117c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_notask++;
17127c478bd9Sstevel@tonic-gate 		return;
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	/*
17167c478bd9Sstevel@tonic-gate 	 * Copy status block into a local buffer.
17177c478bd9Sstevel@tonic-gate 	 *
17187c478bd9Sstevel@tonic-gate 	 * Note: (ref: B.2) "SBP-2 permits the return of a status block between
17197c478bd9Sstevel@tonic-gate 	 *	two and eight quadlets in length. When a truncated status block
17207c478bd9Sstevel@tonic-gate 	 *	is stored, the omited quadlets shall be interpreted as if zero
17217c478bd9Sstevel@tonic-gate 	 *	values were stored."
17227c478bd9Sstevel@tonic-gate 	 */
17237c478bd9Sstevel@tonic-gate 	bzero(&task->ts_status, sizeof (sbp2_status_t));
17247c478bd9Sstevel@tonic-gate 	bcopy((*bpp)->b_rptr, &task->ts_status, len);
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	mutex_enter(&ap->a_mutex);
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	if ((timeout_id = task->ts_timeout_id) != 0) {
17317c478bd9Sstevel@tonic-gate 		task->ts_timeout_id = 0;
17327c478bd9Sstevel@tonic-gate 		(void) untimeout(timeout_id);
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	/* determine agent state */
17367c478bd9Sstevel@tonic-gate 	if (st->st_param & SBP2_ST_DEAD) {
17377c478bd9Sstevel@tonic-gate 		ap->a_state = SBP2_AGENT_STATE_DEAD;
17387c478bd9Sstevel@tonic-gate 		tp->t_stat.stat_status_dead++;
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	/* avoid race with other callbacks */
17427c478bd9Sstevel@tonic-gate 	if (task->ts_state != SBP2_TASK_PEND) {
17437c478bd9Sstevel@tonic-gate 		mutex_exit(&ap->a_mutex);
17447c478bd9Sstevel@tonic-gate 		return;
17457c478bd9Sstevel@tonic-gate 	}
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	if (task == ap->a_active_task) {
17487c478bd9Sstevel@tonic-gate 		ap->a_active_task = NULL;
17497c478bd9Sstevel@tonic-gate 	}
17507c478bd9Sstevel@tonic-gate 	task->ts_error = SBP2_TASK_ERR_NONE;
17517c478bd9Sstevel@tonic-gate 	task->ts_state = SBP2_TASK_COMP;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	mutex_exit(&ap->a_mutex);
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	sp->s_status_cb(sp->s_status_cb_arg, task);	/* notify the driver */
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate /*
17597c478bd9Sstevel@tonic-gate  *
17607c478bd9Sstevel@tonic-gate  * --- other
17617c478bd9Sstevel@tonic-gate  *
17627c478bd9Sstevel@tonic-gate  * since mgt agent is shared between LUNs and login sessions,
17637c478bd9Sstevel@tonic-gate  * it is safer to serialize mgt requests
17647c478bd9Sstevel@tonic-gate  */
17657c478bd9Sstevel@tonic-gate static void
sbp2_mgt_agent_acquire(sbp2_tgt_t * tp)17667c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(sbp2_tgt_t *tp)
17677c478bd9Sstevel@tonic-gate {
17687c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
17697c478bd9Sstevel@tonic-gate 	while (tp->t_mgt_agent_acquired) {
17707c478bd9Sstevel@tonic-gate 		cv_wait(&tp->t_mgt_agent_cv, &tp->t_mutex);
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 	tp->t_mgt_agent_acquired = B_TRUE;
17737c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate static void
sbp2_mgt_agent_release(sbp2_tgt_t * tp)17777c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(sbp2_tgt_t *tp)
17787c478bd9Sstevel@tonic-gate {
17797c478bd9Sstevel@tonic-gate 	mutex_enter(&tp->t_mutex);
17807c478bd9Sstevel@tonic-gate 	tp->t_mgt_agent_acquired = B_FALSE;
17817c478bd9Sstevel@tonic-gate 	cv_signal(&tp->t_mgt_agent_cv);	/* wake next waiter */
17827c478bd9Sstevel@tonic-gate 	mutex_exit(&tp->t_mutex);
17837c478bd9Sstevel@tonic-gate }
1784