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