xref: /illumos-gate/usr/src/uts/intel/io/dktp/hba/ghd/ghd.c (revision 14e0668f)
1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
5507c3241Smlf  * Common Development and Distribution License (the "License").
6507c3241Smlf  * You may not use this file except in compliance with the License.
7507c3241Smlf  *
8507c3241Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf  * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf  * See the License for the specific language governing permissions
11507c3241Smlf  * and limitations under the License.
12507c3241Smlf  *
13507c3241Smlf  * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf  * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf  *
19507c3241Smlf  * CDDL HEADER END
20507c3241Smlf  */
21507c3241Smlf 
22507c3241Smlf /*
23*14e0668fSzhongyan gu - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24507c3241Smlf  * Use is subject to license terms.
25507c3241Smlf  */
26507c3241Smlf 
27507c3241Smlf 
28507c3241Smlf #include <sys/types.h>
29507c3241Smlf #include <sys/kmem.h>
30507c3241Smlf #include <sys/debug.h>
31507c3241Smlf #include <sys/scsi/scsi.h>
32507c3241Smlf 
33507c3241Smlf #include "ghd.h"
34507c3241Smlf 
35507c3241Smlf /* ghd_poll() function codes: */
36507c3241Smlf typedef enum {
37507c3241Smlf 	GHD_POLL_REQUEST,	/* wait for a specific request */
38507c3241Smlf 	GHD_POLL_DEVICE,	/* wait for a specific device to idle */
39507c3241Smlf 	GHD_POLL_ALL		/* wait for the whole bus to idle */
40507c3241Smlf } gpoll_t;
41507c3241Smlf 
42507c3241Smlf /*
43507c3241Smlf  * Local functions:
44507c3241Smlf  */
45507c3241Smlf static	gcmd_t	*ghd_doneq_get(ccc_t *cccp);
46507c3241Smlf static	void	 ghd_doneq_pollmode_enter(ccc_t *cccp);
47507c3241Smlf static	void	 ghd_doneq_pollmode_exit(ccc_t *cccp);
48507c3241Smlf static	uint_t	 ghd_doneq_process(caddr_t arg);
49507c3241Smlf static	void	 ghd_do_reset_notify_callbacks(ccc_t *cccp);
50507c3241Smlf 
51507c3241Smlf static	int	 ghd_poll(ccc_t *cccp, gpoll_t polltype, ulong_t polltime,
52507c3241Smlf 			gcmd_t *poll_gcmdp, gtgt_t *gtgtp, void *intr_status);
53507c3241Smlf 
54507c3241Smlf 
55507c3241Smlf /*
56507c3241Smlf  * Local configuration variables
57507c3241Smlf  */
58*14e0668fSzhongyan gu - Sun Microsystems - Beijing China #define	DEFAULT_GHD_TIMEOUT    50000	/* Amount of time to poll(50ms) */
59507c3241Smlf 
60*14e0668fSzhongyan gu - Sun Microsystems - Beijing China ulong_t	ghd_tran_abort_timeout = DEFAULT_GHD_TIMEOUT;
61*14e0668fSzhongyan gu - Sun Microsystems - Beijing China ulong_t	ghd_tran_abort_lun_timeout = DEFAULT_GHD_TIMEOUT;
62*14e0668fSzhongyan gu - Sun Microsystems - Beijing China ulong_t	ghd_tran_reset_target_timeout = DEFAULT_GHD_TIMEOUT;
63*14e0668fSzhongyan gu - Sun Microsystems - Beijing China ulong_t	ghd_tran_reset_bus_timeout = DEFAULT_GHD_TIMEOUT;
64507c3241Smlf 
65507c3241Smlf static int
ghd_doneq_init(ccc_t * cccp)66507c3241Smlf ghd_doneq_init(ccc_t *cccp)
67507c3241Smlf {
68507c3241Smlf 	ddi_iblock_cookie_t iblock;
69507c3241Smlf 
70507c3241Smlf 	L2_INIT(&cccp->ccc_doneq);
71507c3241Smlf 	cccp->ccc_hba_pollmode = TRUE;
72507c3241Smlf 
73507c3241Smlf 	if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
74507c3241Smlf 	    &cccp->ccc_doneq_softid, &iblock, NULL,
75507c3241Smlf 	    ghd_doneq_process, (caddr_t)cccp) != DDI_SUCCESS) {
76507c3241Smlf 		GDBG_ERROR(("ghd_doneq_init: add softintr failed cccp 0x%p\n",
77507c3241Smlf 		    (void *)cccp));
78507c3241Smlf 		return (FALSE);
79507c3241Smlf 	}
80507c3241Smlf 
81507c3241Smlf 	mutex_init(&cccp->ccc_doneq_mutex, NULL, MUTEX_DRIVER, iblock);
82507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
83507c3241Smlf 	return (TRUE);
84507c3241Smlf }
85507c3241Smlf 
86507c3241Smlf /*
87507c3241Smlf  * ghd_complete():
88507c3241Smlf  *
89507c3241Smlf  *	The HBA driver calls this entry point when it's completely
90507c3241Smlf  *	done processing a request.
91507c3241Smlf  *
92507c3241Smlf  *	See the GHD_COMPLETE_INLINE() macro in ghd.h for the actual code.
93507c3241Smlf  */
94507c3241Smlf 
95507c3241Smlf void
ghd_complete(ccc_t * cccp,gcmd_t * gcmdp)96507c3241Smlf ghd_complete(ccc_t *cccp, gcmd_t *gcmdp)
97507c3241Smlf {
98507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
99507c3241Smlf 	GHD_COMPLETE_INLINE(cccp, gcmdp);
100507c3241Smlf }
101507c3241Smlf 
102507c3241Smlf 
103507c3241Smlf /*
104507c3241Smlf  * ghd_doneq_put_head():
105507c3241Smlf  *
106507c3241Smlf  *	Mark the request done and prepend it to the doneq.
107507c3241Smlf  *	See the GHD_DONEQ_PUT_HEAD_INLINE() macros in ghd.h for
108507c3241Smlf  *	the actual code.
109507c3241Smlf  */
110507c3241Smlf void
ghd_doneq_put_head(ccc_t * cccp,gcmd_t * gcmdp)111507c3241Smlf ghd_doneq_put_head(ccc_t *cccp, gcmd_t *gcmdp)
112507c3241Smlf {
113507c3241Smlf 	GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp)
114507c3241Smlf }
115507c3241Smlf 
116507c3241Smlf /*
117507c3241Smlf  * ghd_doneq_put_tail():
118507c3241Smlf  *
119507c3241Smlf  *	Mark the request done and append it to the doneq.
120507c3241Smlf  *	See the GHD_DONEQ_PUT_TAIL_INLINE() macros in ghd.h for
121507c3241Smlf  *	the actual code.
122507c3241Smlf  */
123507c3241Smlf void
ghd_doneq_put_tail(ccc_t * cccp,gcmd_t * gcmdp)124507c3241Smlf ghd_doneq_put_tail(ccc_t *cccp, gcmd_t *gcmdp)
125507c3241Smlf {
126507c3241Smlf 	GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp)
127507c3241Smlf }
128507c3241Smlf 
129507c3241Smlf static gcmd_t	*
ghd_doneq_get(ccc_t * cccp)130507c3241Smlf ghd_doneq_get(ccc_t *cccp)
131507c3241Smlf {
132507c3241Smlf 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
133507c3241Smlf 	gcmd_t	 *gcmdp;
134507c3241Smlf 
135507c3241Smlf 	mutex_enter(doneq_mutexp);
136507c3241Smlf 	if ((gcmdp = L2_next(&cccp->ccc_doneq)) != NULL)
137507c3241Smlf 		L2_delete(&gcmdp->cmd_q);
138507c3241Smlf 	mutex_exit(doneq_mutexp);
139507c3241Smlf 	return (gcmdp);
140507c3241Smlf }
141507c3241Smlf 
142507c3241Smlf 
143507c3241Smlf static void
ghd_doneq_pollmode_enter(ccc_t * cccp)144507c3241Smlf ghd_doneq_pollmode_enter(ccc_t *cccp)
145507c3241Smlf {
146507c3241Smlf 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
147507c3241Smlf 
148507c3241Smlf 	mutex_enter(doneq_mutexp);
149507c3241Smlf 	cccp->ccc_hba_pollmode = TRUE;
150507c3241Smlf 	mutex_exit(doneq_mutexp);
151507c3241Smlf }
152507c3241Smlf 
153507c3241Smlf 
154507c3241Smlf static void
ghd_doneq_pollmode_exit(ccc_t * cccp)155507c3241Smlf ghd_doneq_pollmode_exit(ccc_t *cccp)
156507c3241Smlf {
157507c3241Smlf 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
158507c3241Smlf 
159507c3241Smlf 	mutex_enter(doneq_mutexp);
160507c3241Smlf 	cccp->ccc_hba_pollmode = FALSE;
161507c3241Smlf 	mutex_exit(doneq_mutexp);
162507c3241Smlf 
163507c3241Smlf 	/* trigger software interrupt for the completion callbacks */
1641dc8bc23Szk 	if (!L2_EMPTY(&cccp->ccc_doneq)) {
1651dc8bc23Szk 		/*
1661dc8bc23Szk 		 * If we are panicking we should just call the completion
1671dc8bc23Szk 		 * function directly as we can not use soft interrupts
1681dc8bc23Szk 		 * or timeouts during panic.
1691dc8bc23Szk 		 */
1701dc8bc23Szk 		if (!ddi_in_panic())
1711dc8bc23Szk 			ddi_trigger_softintr(cccp->ccc_doneq_softid);
1721dc8bc23Szk 		else
1731dc8bc23Szk 			(void) ghd_doneq_process((caddr_t)cccp);
1741dc8bc23Szk 	}
175507c3241Smlf }
176507c3241Smlf 
177507c3241Smlf 
178507c3241Smlf /* ***************************************************************** */
179507c3241Smlf 
180507c3241Smlf /*
181507c3241Smlf  *
182507c3241Smlf  * ghd_doneq_process()
183507c3241Smlf  *
184507c3241Smlf  *	This function is called directly from the software interrupt
185507c3241Smlf  *	handler.
186507c3241Smlf  *
187507c3241Smlf  *	The doneq is protected by a separate mutex than the
188507c3241Smlf  *	HBA mutex in order to avoid mutex contention on MP systems.
189507c3241Smlf  *
190507c3241Smlf  */
191507c3241Smlf 
192507c3241Smlf static uint_t
ghd_doneq_process(caddr_t arg)193507c3241Smlf ghd_doneq_process(caddr_t arg)
194507c3241Smlf {
195507c3241Smlf 	ccc_t *cccp =	(ccc_t *)arg;
196507c3241Smlf 	kmutex_t	*doneq_mutexp;
197507c3241Smlf 	gcmd_t		*gcmdp;
198507c3241Smlf 	int			rc = DDI_INTR_UNCLAIMED;
199507c3241Smlf 
200507c3241Smlf 	doneq_mutexp = &cccp->ccc_doneq_mutex;
201507c3241Smlf 
202507c3241Smlf 	for (;;) {
203507c3241Smlf 		mutex_enter(doneq_mutexp);
204507c3241Smlf 		/* skip if FLAG_NOINTR request in progress */
205507c3241Smlf 		if (cccp->ccc_hba_pollmode)
206507c3241Smlf 			break;
207507c3241Smlf 		/* pop the first one from the done Q */
208507c3241Smlf 		if ((gcmdp = L2_next(&cccp->ccc_doneq)) == NULL)
209507c3241Smlf 			break;
210507c3241Smlf 		L2_delete(&gcmdp->cmd_q);
211507c3241Smlf 
212507c3241Smlf 		if (gcmdp->cmd_flags & GCMDFLG_RESET_NOTIFY) {
213507c3241Smlf 			/* special request; processed here and discarded */
214507c3241Smlf 			ghd_do_reset_notify_callbacks(cccp);
215507c3241Smlf 			ghd_gcmd_free(gcmdp);
216507c3241Smlf 			mutex_exit(doneq_mutexp);
217507c3241Smlf 			continue;
218507c3241Smlf 		}
219507c3241Smlf 
220507c3241Smlf 		/*
221507c3241Smlf 		 * drop the mutex since completion
222507c3241Smlf 		 * function can re-enter the top half via
223507c3241Smlf 		 * ghd_transport()
224507c3241Smlf 		 */
225507c3241Smlf 		mutex_exit(doneq_mutexp);
226507c3241Smlf 		gcmdp->cmd_state = GCMD_STATE_IDLE;
227507c3241Smlf 		(*cccp->ccc_hba_complete)(cccp->ccc_hba_handle, gcmdp, TRUE);
228507c3241Smlf #ifdef notyet
229507c3241Smlf 		/* I don't think this is ever necessary */
230507c3241Smlf 		rc = DDI_INTR_CLAIMED;
231507c3241Smlf #endif
232507c3241Smlf 	}
233507c3241Smlf 	mutex_exit(doneq_mutexp);
234507c3241Smlf 	return (rc);
235507c3241Smlf }
236507c3241Smlf 
237507c3241Smlf static void
ghd_do_reset_notify_callbacks(ccc_t * cccp)238507c3241Smlf ghd_do_reset_notify_callbacks(ccc_t *cccp)
239507c3241Smlf {
240507c3241Smlf 	ghd_reset_notify_list_t *rnp;
241507c3241Smlf 	L2el_t *rnl = &cccp->ccc_reset_notify_list;
242507c3241Smlf 
243507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_doneq_mutex));
244507c3241Smlf 
245507c3241Smlf 	/* lock the reset notify list while we operate on it */
246507c3241Smlf 	mutex_enter(&cccp->ccc_reset_notify_mutex);
247507c3241Smlf 
248507c3241Smlf 	for (rnp = (ghd_reset_notify_list_t *)L2_next(rnl);
249507c3241Smlf 	    rnp != NULL;
250507c3241Smlf 	    rnp = (ghd_reset_notify_list_t *)L2_next(&rnp->l2_link)) {
251507c3241Smlf 
252507c3241Smlf 		/* don't call if HBA driver didn't set it */
253507c3241Smlf 		if (cccp->ccc_hba_reset_notify_callback) {
254507c3241Smlf 			(*cccp->ccc_hba_reset_notify_callback)(rnp->gtgtp,
255507c3241Smlf 			    rnp->callback, rnp->arg);
256507c3241Smlf 		}
257507c3241Smlf 	}
258507c3241Smlf 	mutex_exit(&cccp->ccc_reset_notify_mutex);
259507c3241Smlf }
260507c3241Smlf 
261507c3241Smlf 
262507c3241Smlf /* ***************************************************************** */
263507c3241Smlf 
264507c3241Smlf 
265507c3241Smlf /*
266507c3241Smlf  * ghd_register()
267507c3241Smlf  *
268507c3241Smlf  *	Do the usual interrupt handler setup stuff.
269507c3241Smlf  *
270507c3241Smlf  *	Also, set up three mutexes: the wait queue mutex, the HBA
271507c3241Smlf  *	mutex, and the done queue mutex. The permitted locking
272507c3241Smlf  *	orders are:
273507c3241Smlf  *
274507c3241Smlf  *		1. enter(waitq)
275507c3241Smlf  *		2. enter(activel)
276507c3241Smlf  *		3. enter(doneq)
277507c3241Smlf  *		4. enter(HBA) then enter(activel)
278507c3241Smlf  *		5. enter(HBA) then enter(doneq)
279507c3241Smlf  *		6. enter(HBA) then enter(waitq)
280507c3241Smlf  *		7. enter(waitq) then tryenter(HBA)
281507c3241Smlf  *
282507c3241Smlf  *	Note: cases 6 and 7 won't deadlock because case 7 is always
283507c3241Smlf  *	mutex_tryenter() call.
284507c3241Smlf  *
285507c3241Smlf  */
286507c3241Smlf 
287507c3241Smlf 
288507c3241Smlf int
ghd_register(char * labelp,ccc_t * cccp,dev_info_t * dip,int inumber,void * hba_handle,int (* ccballoc)(gtgt_t *,gcmd_t *,int,int,int,int),void (* ccbfree)(gcmd_t *),void (* sg_func)(gcmd_t *,ddi_dma_cookie_t *,int,int),int (* hba_start)(void *,gcmd_t *),void (* hba_complete)(void *,gcmd_t *,int),uint_t (* int_handler)(caddr_t),int (* get_status)(void *,void *),void (* process_intr)(void *,void *),int (* timeout_func)(void *,gcmd_t *,gtgt_t *,gact_t,int),tmr_t * tmrp,void (* hba_reset_notify_callback)(gtgt_t *,void (*)(caddr_t),caddr_t))289507c3241Smlf ghd_register(char *labelp,
290507c3241Smlf 	ccc_t	*cccp,
291507c3241Smlf 	dev_info_t *dip,
292507c3241Smlf 	int	inumber,
293507c3241Smlf 	void	*hba_handle,
294507c3241Smlf 	int	(*ccballoc)(gtgt_t *, gcmd_t *, int, int, int, int),
295507c3241Smlf 	void	(*ccbfree)(gcmd_t *),
296507c3241Smlf 	void	(*sg_func)(gcmd_t *, ddi_dma_cookie_t *, int, int),
297507c3241Smlf 	int	(*hba_start)(void *, gcmd_t *),
298507c3241Smlf 	void    (*hba_complete)(void *, gcmd_t *, int),
299507c3241Smlf 	uint_t	(*int_handler)(caddr_t),
300507c3241Smlf 	int	(*get_status)(void *, void *),
301507c3241Smlf 	void	(*process_intr)(void *, void *),
302507c3241Smlf 	int	(*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int),
303507c3241Smlf 	tmr_t	*tmrp,
304507c3241Smlf 	void 	(*hba_reset_notify_callback)(gtgt_t *,
305507c3241Smlf 			void (*)(caddr_t), caddr_t))
306507c3241Smlf {
307507c3241Smlf 
308507c3241Smlf 	cccp->ccc_label = labelp;
309507c3241Smlf 	cccp->ccc_hba_dip = dip;
310507c3241Smlf 	cccp->ccc_ccballoc = ccballoc;
311507c3241Smlf 	cccp->ccc_ccbfree = ccbfree;
312507c3241Smlf 	cccp->ccc_sg_func = sg_func;
313507c3241Smlf 	cccp->ccc_hba_start = hba_start;
314507c3241Smlf 	cccp->ccc_hba_complete = hba_complete;
315507c3241Smlf 	cccp->ccc_process_intr = process_intr;
316507c3241Smlf 	cccp->ccc_get_status = get_status;
317507c3241Smlf 	cccp->ccc_hba_handle = hba_handle;
318507c3241Smlf 	cccp->ccc_hba_reset_notify_callback = hba_reset_notify_callback;
319507c3241Smlf 
320507c3241Smlf 	/* initialize the HBA's list headers */
321507c3241Smlf 	CCCP_INIT(cccp);
322507c3241Smlf 
3239f49ae27Smlf 	if (ddi_get_iblock_cookie(dip, inumber, &cccp->ccc_iblock)
3249f49ae27Smlf 	    != DDI_SUCCESS) {
3259f49ae27Smlf 
326507c3241Smlf 		return (FALSE);
327507c3241Smlf 	}
3289f49ae27Smlf 
329507c3241Smlf 	mutex_init(&cccp->ccc_hba_mutex, NULL, MUTEX_DRIVER, cccp->ccc_iblock);
330507c3241Smlf 
3319f49ae27Smlf 	mutex_init(&cccp->ccc_waitq_mutex, NULL, MUTEX_DRIVER,
3329f49ae27Smlf 	    cccp->ccc_iblock);
3339f49ae27Smlf 
3349f49ae27Smlf 	mutex_init(&cccp->ccc_reset_notify_mutex, NULL, MUTEX_DRIVER,
3359f49ae27Smlf 	    cccp->ccc_iblock);
3369f49ae27Smlf 
3379f49ae27Smlf 	/* Establish interrupt handler */
338507c3241Smlf 	if (ddi_add_intr(dip, inumber, &cccp->ccc_iblock, NULL,
339507c3241Smlf 	    int_handler, (caddr_t)hba_handle) != DDI_SUCCESS) {
340507c3241Smlf 		mutex_destroy(&cccp->ccc_hba_mutex);
3419f49ae27Smlf 		mutex_destroy(&cccp->ccc_waitq_mutex);
3429f49ae27Smlf 		mutex_destroy(&cccp->ccc_reset_notify_mutex);
3439f49ae27Smlf 
344507c3241Smlf 		return (FALSE);
345507c3241Smlf 	}
346507c3241Smlf 
347507c3241Smlf 	if (ghd_timer_attach(cccp, tmrp, timeout_func) == FALSE) {
348507c3241Smlf 		ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
349507c3241Smlf 		mutex_destroy(&cccp->ccc_hba_mutex);
350507c3241Smlf 		mutex_destroy(&cccp->ccc_waitq_mutex);
3519f49ae27Smlf 		mutex_destroy(&cccp->ccc_reset_notify_mutex);
3529f49ae27Smlf 
353507c3241Smlf 		return (FALSE);
354507c3241Smlf 	}
355507c3241Smlf 
356507c3241Smlf 	if (ghd_doneq_init(cccp)) {
3579f49ae27Smlf 
358507c3241Smlf 		return (TRUE);
359507c3241Smlf 	}
360507c3241Smlf 
3619f49ae27Smlf 	/*
3629f49ae27Smlf 	 * ghd_doneq_init() returned error:
3639f49ae27Smlf 	 */
3649f49ae27Smlf 
365507c3241Smlf 	ghd_timer_detach(cccp);
366507c3241Smlf 	ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
367507c3241Smlf 	mutex_destroy(&cccp->ccc_hba_mutex);
368507c3241Smlf 	mutex_destroy(&cccp->ccc_waitq_mutex);
3699f49ae27Smlf 	mutex_destroy(&cccp->ccc_reset_notify_mutex);
3709f49ae27Smlf 
371507c3241Smlf 	return (FALSE);
372507c3241Smlf 
373507c3241Smlf }
374507c3241Smlf 
375507c3241Smlf 
376507c3241Smlf void
ghd_unregister(ccc_t * cccp)377507c3241Smlf ghd_unregister(ccc_t *cccp)
378507c3241Smlf {
379507c3241Smlf 	ghd_timer_detach(cccp);
380507c3241Smlf 	ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
381507c3241Smlf 	ddi_remove_softintr(cccp->ccc_doneq_softid);
382507c3241Smlf 	mutex_destroy(&cccp->ccc_hba_mutex);
383507c3241Smlf 	mutex_destroy(&cccp->ccc_waitq_mutex);
384507c3241Smlf 	mutex_destroy(&cccp->ccc_doneq_mutex);
385507c3241Smlf }
386507c3241Smlf 
387507c3241Smlf 
388507c3241Smlf 
389507c3241Smlf int
ghd_intr(ccc_t * cccp,void * intr_status)390507c3241Smlf ghd_intr(ccc_t *cccp, void *intr_status)
391507c3241Smlf {
392507c3241Smlf 	int (*statfunc)(void *, void *) = cccp->ccc_get_status;
393507c3241Smlf 	void (*processfunc)(void *, void *) = cccp->ccc_process_intr;
394507c3241Smlf 	kmutex_t *waitq_mutexp = &cccp->ccc_waitq_mutex;
395507c3241Smlf 	kmutex_t *hba_mutexp = &cccp->ccc_hba_mutex;
396507c3241Smlf 	void		  *handle = cccp->ccc_hba_handle;
397507c3241Smlf 	int		   rc = DDI_INTR_UNCLAIMED;
398507c3241Smlf 	int		   more;
399507c3241Smlf 
400507c3241Smlf 
401507c3241Smlf 	mutex_enter(hba_mutexp);
402507c3241Smlf 
403507c3241Smlf 	GDBG_INTR(("ghd_intr(): cccp=0x%p status=0x%p\n",
404903a11ebSrh 	    (void *)cccp, intr_status));
405507c3241Smlf 
406507c3241Smlf 	for (;;) {
407507c3241Smlf 		more = FALSE;
408507c3241Smlf 
409507c3241Smlf 		/* process the interrupt status */
410507c3241Smlf 		while ((*statfunc)(handle, intr_status)) {
411507c3241Smlf 			(*processfunc)(handle, intr_status);
412507c3241Smlf 			rc = DDI_INTR_CLAIMED;
413507c3241Smlf 			more = TRUE;
414507c3241Smlf 		}
415507c3241Smlf 		mutex_enter(waitq_mutexp);
416507c3241Smlf 		if (ghd_waitq_process_and_mutex_hold(cccp)) {
417507c3241Smlf 			ASSERT(mutex_owned(hba_mutexp));
418507c3241Smlf 			mutex_exit(waitq_mutexp);
419507c3241Smlf 			continue;
420507c3241Smlf 		}
421507c3241Smlf 		if (more) {
422507c3241Smlf 			mutex_exit(waitq_mutexp);
423507c3241Smlf 			continue;
424507c3241Smlf 		}
425507c3241Smlf 		GDBG_INTR(("ghd_intr(): done cccp=0x%p status=0x%p rc %d\n",
426903a11ebSrh 		    (void *)cccp, intr_status, rc));
427507c3241Smlf 		/*
428507c3241Smlf 		 * Release the mutexes in the opposite order that they
429507c3241Smlf 		 * were acquired to prevent requests queued by
430507c3241Smlf 		 * ghd_transport() from getting hung up in the wait queue.
431507c3241Smlf 		 */
432507c3241Smlf 		mutex_exit(hba_mutexp);
433507c3241Smlf 		mutex_exit(waitq_mutexp);
434507c3241Smlf 		return (rc);
435507c3241Smlf 	}
436507c3241Smlf }
437507c3241Smlf 
438507c3241Smlf static int
ghd_poll(ccc_t * cccp,gpoll_t polltype,ulong_t polltime,gcmd_t * poll_gcmdp,gtgt_t * gtgtp,void * intr_status)439507c3241Smlf ghd_poll(ccc_t	*cccp,
440507c3241Smlf 	gpoll_t	 polltype,
441507c3241Smlf 	ulong_t	 polltime,
442507c3241Smlf 	gcmd_t	*poll_gcmdp,
443507c3241Smlf 	gtgt_t	*gtgtp,
444507c3241Smlf 	void	*intr_status)
445507c3241Smlf {
446507c3241Smlf 	gcmd_t	*gcmdp;
447507c3241Smlf 	L2el_t	 gcmd_hold_queue;
448507c3241Smlf 	int	 got_it = FALSE;
449*14e0668fSzhongyan gu - Sun Microsystems - Beijing China 	clock_t  poll_lbolt;
450507c3241Smlf 	clock_t	 start_lbolt;
451507c3241Smlf 	clock_t	 current_lbolt;
452507c3241Smlf 
453507c3241Smlf 
454507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
455507c3241Smlf 	L2_INIT(&gcmd_hold_queue);
456507c3241Smlf 
457507c3241Smlf 	/* Que hora es? */
458*14e0668fSzhongyan gu - Sun Microsystems - Beijing China 	poll_lbolt = drv_usectohz((clock_t)polltime);
459507c3241Smlf 	start_lbolt = ddi_get_lbolt();
460507c3241Smlf 
461507c3241Smlf 	/* unqueue and save all CMD/CCBs until I find the right one */
462507c3241Smlf 	while (!got_it) {
463507c3241Smlf 
464507c3241Smlf 		/* Give up yet? */
465507c3241Smlf 		current_lbolt = ddi_get_lbolt();
466*14e0668fSzhongyan gu - Sun Microsystems - Beijing China 		if (poll_lbolt && (current_lbolt - start_lbolt >= poll_lbolt))
467507c3241Smlf 			break;
468507c3241Smlf 
469507c3241Smlf 		/*
470507c3241Smlf 		 * delay 1 msec each time around the loop (this is an
471507c3241Smlf 		 * arbitrary delay value, any value should work) except
472507c3241Smlf 		 * zero because some devices don't like being polled too
473507c3241Smlf 		 * fast and it saturates the bus on an MP system.
474507c3241Smlf 		 */
475507c3241Smlf 		drv_usecwait(1000);
476507c3241Smlf 
477507c3241Smlf 		/*
478507c3241Smlf 		 * check for any new device status
479507c3241Smlf 		 */
480507c3241Smlf 		if ((*cccp->ccc_get_status)(cccp->ccc_hba_handle, intr_status))
481507c3241Smlf 			(*cccp->ccc_process_intr)(cccp->ccc_hba_handle,
482507c3241Smlf 			    intr_status);
483507c3241Smlf 
484507c3241Smlf 		/*
485507c3241Smlf 		 * If something completed then try to start the
486507c3241Smlf 		 * next request from the wait queue. Don't release
487507c3241Smlf 		 * the HBA mutex because I don't know whether my
488507c3241Smlf 		 * request(s) is/are on the done queue yet.
489507c3241Smlf 		 */
490507c3241Smlf 		mutex_enter(&cccp->ccc_waitq_mutex);
491507c3241Smlf 		(void) ghd_waitq_process_and_mutex_hold(cccp);
492507c3241Smlf 		mutex_exit(&cccp->ccc_waitq_mutex);
493507c3241Smlf 
494507c3241Smlf 		/*
495507c3241Smlf 		 * Process the first of any timed-out requests.
496507c3241Smlf 		 */
497507c3241Smlf 		ghd_timer_poll(cccp, GHD_TIMER_POLL_ONE);
498507c3241Smlf 
499507c3241Smlf 		/*
500507c3241Smlf 		 * Unqueue all the completed requests, look for mine
501507c3241Smlf 		 */
502507c3241Smlf 		while (gcmdp = ghd_doneq_get(cccp)) {
503507c3241Smlf 			/*
504507c3241Smlf 			 * If we got one and it's my request, then
505507c3241Smlf 			 * we're done.
506507c3241Smlf 			 */
507507c3241Smlf 			if (gcmdp == poll_gcmdp) {
508507c3241Smlf 				poll_gcmdp->cmd_state = GCMD_STATE_IDLE;
509507c3241Smlf 				got_it = TRUE;
510507c3241Smlf 				continue;
511507c3241Smlf 			}
512507c3241Smlf 			/* fifo queue the other cmds on my local list */
513507c3241Smlf 			L2_add(&gcmd_hold_queue, &gcmdp->cmd_q, gcmdp);
514507c3241Smlf 		}
515507c3241Smlf 
516507c3241Smlf 
517507c3241Smlf 		/*
518507c3241Smlf 		 * Check whether we're done yet.
519507c3241Smlf 		 */
520507c3241Smlf 		switch (polltype) {
521507c3241Smlf 		case GHD_POLL_DEVICE:
522507c3241Smlf 			/*
523507c3241Smlf 			 * wait for everything queued on a specific device
524507c3241Smlf 			 */
525507c3241Smlf 			if (GDEV_NACTIVE(gtgtp->gt_gdevp) == 0)
526507c3241Smlf 				got_it = TRUE;
527507c3241Smlf 			break;
528507c3241Smlf 
529507c3241Smlf 		case GHD_POLL_ALL:
530507c3241Smlf 			/*
531507c3241Smlf 			 * if waiting for all outstanding requests and
532507c3241Smlf 			 * if active list is now empty then exit
533507c3241Smlf 			 */
534507c3241Smlf 			if (GHBA_NACTIVE(cccp) == 0)
535507c3241Smlf 				got_it = TRUE;
536507c3241Smlf 			break;
537507c3241Smlf 
538507c3241Smlf 		case GHD_POLL_REQUEST:
539507c3241Smlf 			break;
540507c3241Smlf 
541507c3241Smlf 		}
542507c3241Smlf 	}
543507c3241Smlf 
544507c3241Smlf 	if (L2_EMPTY(&gcmd_hold_queue)) {
545507c3241Smlf 		ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
546507c3241Smlf 		ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
547507c3241Smlf 		return (got_it);
548507c3241Smlf 	}
549507c3241Smlf 
550507c3241Smlf 	/*
551507c3241Smlf 	 * copy the local gcmd_hold_queue back to the doneq so
552507c3241Smlf 	 * that the order of completion callbacks is preserved
553507c3241Smlf 	 */
554507c3241Smlf 	while (gcmdp = L2_next(&gcmd_hold_queue)) {
555507c3241Smlf 		L2_delete(&gcmdp->cmd_q);
556507c3241Smlf 		GHD_DONEQ_PUT_TAIL(cccp, gcmdp);
557507c3241Smlf 	}
558507c3241Smlf 
559507c3241Smlf 	ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
560507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
561507c3241Smlf 	return (got_it);
562507c3241Smlf }
563507c3241Smlf 
564507c3241Smlf 
565507c3241Smlf /*
566507c3241Smlf  * ghd_tran_abort()
567507c3241Smlf  *
568507c3241Smlf  *	Abort specific command on a target.
569507c3241Smlf  *
570507c3241Smlf  */
571507c3241Smlf 
572507c3241Smlf int
ghd_tran_abort(ccc_t * cccp,gcmd_t * gcmdp,gtgt_t * gtgtp,void * intr_status)573507c3241Smlf ghd_tran_abort(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp, void *intr_status)
574507c3241Smlf {
575507c3241Smlf 	gact_t	 action;
576507c3241Smlf 	int	 rc;
577507c3241Smlf 
578507c3241Smlf 	/*
579507c3241Smlf 	 * call the driver's abort_cmd function
580507c3241Smlf 	 */
581507c3241Smlf 
582507c3241Smlf 	mutex_enter(&cccp->ccc_hba_mutex);
583507c3241Smlf 	ghd_doneq_pollmode_enter(cccp);
584507c3241Smlf 
585507c3241Smlf 	switch (gcmdp->cmd_state) {
586507c3241Smlf 	case GCMD_STATE_WAITQ:
587507c3241Smlf 		/* not yet started */
588507c3241Smlf 		action = GACTION_EARLY_ABORT;
589507c3241Smlf 		break;
590507c3241Smlf 
591507c3241Smlf 	case GCMD_STATE_ACTIVE:
592507c3241Smlf 		/* in progress */
593507c3241Smlf 		action = GACTION_ABORT_CMD;
594507c3241Smlf 		break;
595507c3241Smlf 
596507c3241Smlf 	default:
597507c3241Smlf 		/* everything else, probably already being aborted */
598507c3241Smlf 		rc = FALSE;
599507c3241Smlf 		goto exit;
600507c3241Smlf 	}
601507c3241Smlf 
602507c3241Smlf 	/* stop the timer and remove it from the active list */
603507c3241Smlf 	GHD_TIMER_STOP(cccp, gcmdp);
604507c3241Smlf 
605507c3241Smlf 	/* start a new timer and send out the abort command */
606507c3241Smlf 	ghd_timer_newstate(cccp, gcmdp, gtgtp, action, GHD_TGTREQ);
607507c3241Smlf 
608507c3241Smlf 	/* wait for the abort to complete */
609507c3241Smlf 	if (rc = ghd_poll(cccp, GHD_POLL_REQUEST, ghd_tran_abort_timeout,
610507c3241Smlf 	    gcmdp, gtgtp, intr_status)) {
611507c3241Smlf 		gcmdp->cmd_state = GCMD_STATE_DONEQ;
612507c3241Smlf 		GHD_DONEQ_PUT_TAIL(cccp, gcmdp);
613507c3241Smlf 	}
614507c3241Smlf 
615507c3241Smlf exit:
616507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
617507c3241Smlf 
618507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
619507c3241Smlf 	ghd_waitq_process_and_mutex_exit(cccp);
620507c3241Smlf 
621507c3241Smlf 	return (rc);
622507c3241Smlf }
623507c3241Smlf 
624507c3241Smlf 
625507c3241Smlf /*
626507c3241Smlf  * ghd_tran_abort_lun()
627507c3241Smlf  *
628507c3241Smlf  *	Abort all commands on a specific target.
629507c3241Smlf  *
630507c3241Smlf  */
631507c3241Smlf 
632507c3241Smlf int
ghd_tran_abort_lun(ccc_t * cccp,gtgt_t * gtgtp,void * intr_status)633507c3241Smlf ghd_tran_abort_lun(ccc_t *cccp,	gtgt_t *gtgtp, void *intr_status)
634507c3241Smlf {
635507c3241Smlf 	int	 rc;
636507c3241Smlf 
637507c3241Smlf 	/*
638507c3241Smlf 	 * call the HBA driver's abort_device function
639507c3241Smlf 	 */
640507c3241Smlf 
641507c3241Smlf 	mutex_enter(&cccp->ccc_hba_mutex);
642507c3241Smlf 	ghd_doneq_pollmode_enter(cccp);
643507c3241Smlf 
644507c3241Smlf 	/* send out the abort device request */
645507c3241Smlf 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_ABORT_DEV, GHD_TGTREQ);
646507c3241Smlf 
647507c3241Smlf 	/* wait for the device to go idle */
648507c3241Smlf 	rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_abort_lun_timeout,
6491dc8bc23Szk 	    NULL, gtgtp, intr_status);
650507c3241Smlf 
651507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
652507c3241Smlf 
653507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
654507c3241Smlf 	ghd_waitq_process_and_mutex_exit(cccp);
655507c3241Smlf 
656507c3241Smlf 	return (rc);
657507c3241Smlf }
658507c3241Smlf 
659507c3241Smlf 
660507c3241Smlf 
661507c3241Smlf /*
662507c3241Smlf  * ghd_tran_reset_target()
663507c3241Smlf  *
664507c3241Smlf  *	reset the target device
665507c3241Smlf  *
666507c3241Smlf  *
667507c3241Smlf  */
668507c3241Smlf 
669507c3241Smlf int
ghd_tran_reset_target(ccc_t * cccp,gtgt_t * gtgtp,void * intr_status)670507c3241Smlf ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status)
671507c3241Smlf {
672507c3241Smlf 	int rc = TRUE;
673507c3241Smlf 
674507c3241Smlf 
675507c3241Smlf 	mutex_enter(&cccp->ccc_hba_mutex);
676507c3241Smlf 	ghd_doneq_pollmode_enter(cccp);
677507c3241Smlf 
678507c3241Smlf 	/* send out the device reset request */
679507c3241Smlf 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_TARGET, GHD_TGTREQ);
680507c3241Smlf 
681507c3241Smlf 	/* wait for the device to reset */
682507c3241Smlf 	rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_reset_target_timeout,
6831dc8bc23Szk 	    NULL, gtgtp, intr_status);
684507c3241Smlf 
685507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
686507c3241Smlf 
687507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
688507c3241Smlf 	ghd_waitq_process_and_mutex_exit(cccp);
689507c3241Smlf 
690507c3241Smlf 	return (rc);
691507c3241Smlf }
692507c3241Smlf 
693507c3241Smlf 
694507c3241Smlf 
695507c3241Smlf /*
696507c3241Smlf  * ghd_tran_reset_bus()
697507c3241Smlf  *
698507c3241Smlf  *	reset the scsi bus
699507c3241Smlf  *
700507c3241Smlf  */
701507c3241Smlf 
702507c3241Smlf int
ghd_tran_reset_bus(ccc_t * cccp,gtgt_t * gtgtp,void * intr_status)703507c3241Smlf ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status)
704507c3241Smlf {
705507c3241Smlf 	int	rc;
706507c3241Smlf 
707507c3241Smlf 	mutex_enter(&cccp->ccc_hba_mutex);
708507c3241Smlf 	ghd_doneq_pollmode_enter(cccp);
709507c3241Smlf 
710507c3241Smlf 	/* send out the bus reset request */
711507c3241Smlf 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_BUS, GHD_TGTREQ);
712507c3241Smlf 
713507c3241Smlf 	/*
714507c3241Smlf 	 * Wait for all active requests on this HBA to complete
715507c3241Smlf 	 */
716507c3241Smlf 	rc = ghd_poll(cccp, GHD_POLL_ALL, ghd_tran_reset_bus_timeout,
7171dc8bc23Szk 	    NULL, NULL, intr_status);
718507c3241Smlf 
719507c3241Smlf 
720507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
721507c3241Smlf 
722507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
723507c3241Smlf 	ghd_waitq_process_and_mutex_exit(cccp);
724507c3241Smlf 
725507c3241Smlf 	return (rc);
726507c3241Smlf }
727507c3241Smlf 
728507c3241Smlf 
729507c3241Smlf int
ghd_transport(ccc_t * cccp,gcmd_t * gcmdp,gtgt_t * gtgtp,ulong_t timeout,int polled,void * intr_status)730507c3241Smlf ghd_transport(ccc_t	*cccp,
731507c3241Smlf 		gcmd_t	*gcmdp,
732507c3241Smlf 		gtgt_t	*gtgtp,
733507c3241Smlf 		ulong_t	 timeout,
734507c3241Smlf 		int	 polled,
735507c3241Smlf 		void	*intr_status)
736507c3241Smlf {
737507c3241Smlf 	gdev_t	*gdevp = gtgtp->gt_gdevp;
738507c3241Smlf 
739507c3241Smlf 	ASSERT(!mutex_owned(&cccp->ccc_hba_mutex));
740507c3241Smlf 	ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
741507c3241Smlf 
742507c3241Smlf 	if (polled) {
743507c3241Smlf 		/*
744507c3241Smlf 		 * Grab the HBA mutex so no other requests are started
745507c3241Smlf 		 * until after this one completes.
746507c3241Smlf 		 */
747507c3241Smlf 		mutex_enter(&cccp->ccc_hba_mutex);
748507c3241Smlf 
749507c3241Smlf 		GDBG_START(("ghd_transport: polled"
7501dc8bc23Szk 		    " cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n",
751903a11ebSrh 		    (void *)cccp, (void *)gdevp, (void *)gtgtp, (void *)gcmdp));
752507c3241Smlf 
753507c3241Smlf 		/*
754507c3241Smlf 		 * Lock the doneq so no other thread flushes the Q.
755507c3241Smlf 		 */
756507c3241Smlf 		ghd_doneq_pollmode_enter(cccp);
757507c3241Smlf 	}
758507c3241Smlf #if defined(GHD_DEBUG) || defined(__lint)
759507c3241Smlf 	else {
760507c3241Smlf 		GDBG_START(("ghd_transport: non-polled"
7611dc8bc23Szk 		    " cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n",
762903a11ebSrh 		    (void *)cccp, (void *)gdevp, (void *)gtgtp, (void *)gcmdp));
763507c3241Smlf 	}
764507c3241Smlf #endif
765507c3241Smlf 	/*
766507c3241Smlf 	 * add this request to the tail of the waitq
767507c3241Smlf 	 */
768507c3241Smlf 	gcmdp->cmd_waitq_level = 1;
769507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
770507c3241Smlf 	L2_add(&GDEV_QHEAD(gdevp), &gcmdp->cmd_q, gcmdp);
771507c3241Smlf 
772507c3241Smlf 	/*
773507c3241Smlf 	 * Add this request to the packet timer active list and start its
774507c3241Smlf 	 * abort timer.
775507c3241Smlf 	 */
776507c3241Smlf 	gcmdp->cmd_state = GCMD_STATE_WAITQ;
777507c3241Smlf 	ghd_timer_start(cccp, gcmdp, timeout);
778507c3241Smlf 
779507c3241Smlf 
780507c3241Smlf 	/*
781507c3241Smlf 	 * Check the device wait queue throttle and perhaps move
782507c3241Smlf 	 * some requests to the end of the HBA wait queue.
783507c3241Smlf 	 */
784507c3241Smlf 	ghd_waitq_shuffle_up(cccp, gdevp);
785507c3241Smlf 
786507c3241Smlf 	if (!polled) {
787507c3241Smlf 		/*
788507c3241Smlf 		 * See if the HBA mutex is available but use the
789507c3241Smlf 		 * tryenter so I don't deadlock.
790507c3241Smlf 		 */
791507c3241Smlf 		if (!mutex_tryenter(&cccp->ccc_hba_mutex)) {
792507c3241Smlf 			/* The HBA mutex isn't available */
793903a11ebSrh 			GDBG_START(("ghd_transport: !mutex cccp 0x%p\n",
794903a11ebSrh 			    (void *)cccp));
795507c3241Smlf 			mutex_exit(&cccp->ccc_waitq_mutex);
796507c3241Smlf 			return (TRAN_ACCEPT);
797507c3241Smlf 		}
798903a11ebSrh 		GDBG_START(("ghd_transport: got mutex cccp 0x%p\n",
799903a11ebSrh 		    (void *)cccp));
800507c3241Smlf 
801507c3241Smlf 		/*
802507c3241Smlf 		 * start as many requests as possible from the head
803507c3241Smlf 		 * of the HBA wait queue
804507c3241Smlf 		 */
805507c3241Smlf 
806507c3241Smlf 		ghd_waitq_process_and_mutex_exit(cccp);
807507c3241Smlf 
808507c3241Smlf 		ASSERT(!mutex_owned(&cccp->ccc_hba_mutex));
809507c3241Smlf 		ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
810507c3241Smlf 
811507c3241Smlf 		return (TRAN_ACCEPT);
812507c3241Smlf 	}
813507c3241Smlf 
814507c3241Smlf 
815507c3241Smlf 	/*
816507c3241Smlf 	 * If polled mode (FLAG_NOINTR specified in scsi_pkt flags),
817507c3241Smlf 	 * then ghd_poll() waits until the request completes or times out
818507c3241Smlf 	 * before returning.
819507c3241Smlf 	 */
820507c3241Smlf 
821507c3241Smlf 	mutex_exit(&cccp->ccc_waitq_mutex);
822507c3241Smlf 	(void) ghd_poll(cccp, GHD_POLL_REQUEST, 0, gcmdp, gtgtp, intr_status);
823507c3241Smlf 	ghd_doneq_pollmode_exit(cccp);
824507c3241Smlf 
825507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
826507c3241Smlf 	ghd_waitq_process_and_mutex_exit(cccp);
827507c3241Smlf 
828507c3241Smlf 	/* call HBA's completion function but don't do callback to target */
829507c3241Smlf 	(*cccp->ccc_hba_complete)(cccp->ccc_hba_handle, gcmdp, FALSE);
830507c3241Smlf 
831903a11ebSrh 	GDBG_START(("ghd_transport: polled done cccp 0x%p\n", (void *)cccp));
832507c3241Smlf 	return (TRAN_ACCEPT);
833507c3241Smlf }
834507c3241Smlf 
ghd_reset_notify(ccc_t * cccp,gtgt_t * gtgtp,int flag,void (* callback)(caddr_t),caddr_t arg)835507c3241Smlf int ghd_reset_notify(ccc_t 	*cccp,
836507c3241Smlf 			gtgt_t *gtgtp,
837507c3241Smlf 			int 	flag,
838507c3241Smlf 			void 	(*callback)(caddr_t),
839507c3241Smlf 			caddr_t arg)
840507c3241Smlf {
841507c3241Smlf 	ghd_reset_notify_list_t *rnp;
842507c3241Smlf 	int rc = FALSE;
843507c3241Smlf 
844507c3241Smlf 	switch (flag) {
845507c3241Smlf 
846507c3241Smlf 	case SCSI_RESET_NOTIFY:
847507c3241Smlf 
848507c3241Smlf 		rnp = (ghd_reset_notify_list_t *)kmem_zalloc(sizeof (*rnp),
849507c3241Smlf 		    KM_SLEEP);
850507c3241Smlf 		rnp->gtgtp = gtgtp;
851507c3241Smlf 		rnp->callback = callback;
852507c3241Smlf 		rnp->arg = arg;
853507c3241Smlf 
854507c3241Smlf 		mutex_enter(&cccp->ccc_reset_notify_mutex);
855507c3241Smlf 		L2_add(&cccp->ccc_reset_notify_list, &rnp->l2_link,
856507c3241Smlf 		    (void *)rnp);
857507c3241Smlf 		mutex_exit(&cccp->ccc_reset_notify_mutex);
858507c3241Smlf 
859507c3241Smlf 		rc = TRUE;
860507c3241Smlf 
861507c3241Smlf 		break;
862507c3241Smlf 
863507c3241Smlf 	case SCSI_RESET_CANCEL:
864507c3241Smlf 
865507c3241Smlf 		mutex_enter(&cccp->ccc_reset_notify_mutex);
866507c3241Smlf 		for (rnp = (ghd_reset_notify_list_t *)
8671dc8bc23Szk 		    L2_next(&cccp->ccc_reset_notify_list);
868507c3241Smlf 		    rnp != NULL;
869507c3241Smlf 		    rnp = (ghd_reset_notify_list_t *)L2_next(&rnp->l2_link)) {
870507c3241Smlf 			if (rnp->gtgtp == gtgtp &&
871507c3241Smlf 			    rnp->callback == callback &&
872507c3241Smlf 			    rnp->arg == arg) {
873507c3241Smlf 				L2_delete(&rnp->l2_link);
874507c3241Smlf 				kmem_free(rnp, sizeof (*rnp));
875507c3241Smlf 				rc = TRUE;
876507c3241Smlf 			}
877507c3241Smlf 		}
878507c3241Smlf 		mutex_exit(&cccp->ccc_reset_notify_mutex);
879507c3241Smlf 		break;
880507c3241Smlf 
881507c3241Smlf 	default:
882507c3241Smlf 		rc = FALSE;
883507c3241Smlf 		break;
884507c3241Smlf 	}
885507c3241Smlf 
886507c3241Smlf 	return (rc);
887507c3241Smlf }
888507c3241Smlf 
889507c3241Smlf /*
890507c3241Smlf  * freeze the HBA waitq output (see ghd_waitq_process_and_mutex_hold),
891507c3241Smlf  * presumably because of a SCSI reset, for delay milliseconds.
892507c3241Smlf  */
893507c3241Smlf 
894507c3241Smlf void
ghd_freeze_waitq(ccc_t * cccp,int delay)895507c3241Smlf ghd_freeze_waitq(ccc_t *cccp, int delay)
896507c3241Smlf {
897507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
898507c3241Smlf 
899507c3241Smlf 	/* freeze the waitq for delay milliseconds */
900507c3241Smlf 
901507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
902507c3241Smlf 	cccp->ccc_waitq_freezetime = ddi_get_lbolt();
903507c3241Smlf 	cccp->ccc_waitq_freezedelay = delay;
904507c3241Smlf 	cccp->ccc_waitq_frozen = 1;
905507c3241Smlf 	mutex_exit(&cccp->ccc_waitq_mutex);
906507c3241Smlf }
907507c3241Smlf 
908507c3241Smlf void
ghd_queue_hold(ccc_t * cccp)909507c3241Smlf ghd_queue_hold(ccc_t *cccp)
910507c3241Smlf {
911507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
912507c3241Smlf 
913507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
914507c3241Smlf 	cccp->ccc_waitq_held = 1;
915507c3241Smlf 	mutex_exit(&cccp->ccc_waitq_mutex);
916507c3241Smlf }
917507c3241Smlf 
918507c3241Smlf void
ghd_queue_unhold(ccc_t * cccp)919507c3241Smlf ghd_queue_unhold(ccc_t *cccp)
920507c3241Smlf {
921507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
922507c3241Smlf 
923507c3241Smlf 	mutex_enter(&cccp->ccc_waitq_mutex);
924507c3241Smlf 	cccp->ccc_waitq_held = 0;
925507c3241Smlf 	mutex_exit(&cccp->ccc_waitq_mutex);
926507c3241Smlf }
927507c3241Smlf 
928507c3241Smlf 
929507c3241Smlf 
930507c3241Smlf /*
931507c3241Smlf  * Trigger previously-registered reset notifications
932507c3241Smlf  */
933507c3241Smlf 
934507c3241Smlf void
ghd_trigger_reset_notify(ccc_t * cccp)935507c3241Smlf ghd_trigger_reset_notify(ccc_t *cccp)
936507c3241Smlf {
937507c3241Smlf 	gcmd_t *gcmdp;
938507c3241Smlf 
939507c3241Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
940507c3241Smlf 
941507c3241Smlf 	/* create magic doneq entry */
942507c3241Smlf 
943507c3241Smlf 	gcmdp = ghd_gcmd_alloc((gtgt_t *)NULL, 0, TRUE);
944507c3241Smlf 	gcmdp->cmd_flags = GCMDFLG_RESET_NOTIFY;
945507c3241Smlf 
946507c3241Smlf 	/* put at head of doneq so it's processed ASAP */
947507c3241Smlf 
948507c3241Smlf 	GHD_DONEQ_PUT_HEAD(cccp, gcmdp);
949507c3241Smlf }
950