xref: /illumos-gate/usr/src/uts/intel/io/dktp/hba/ghd/ghd.c (revision 10a4fa49f51ed9ae1c857a626de6ce9ebf41661a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/kmem.h>
31 #include <sys/debug.h>
32 #include <sys/scsi/scsi.h>
33 
34 #include "ghd.h"
35 
36 /* ghd_poll() function codes: */
37 typedef enum {
38 	GHD_POLL_REQUEST,	/* wait for a specific request */
39 	GHD_POLL_DEVICE,	/* wait for a specific device to idle */
40 	GHD_POLL_ALL		/* wait for the whole bus to idle */
41 } gpoll_t;
42 
43 /*
44  * Local functions:
45  */
46 static	gcmd_t	*ghd_doneq_get(ccc_t *cccp);
47 static	void	 ghd_doneq_pollmode_enter(ccc_t *cccp);
48 static	void	 ghd_doneq_pollmode_exit(ccc_t *cccp);
49 static	uint_t	 ghd_doneq_process(caddr_t arg);
50 static	void	 ghd_do_reset_notify_callbacks(ccc_t *cccp);
51 
52 static	uint_t	 ghd_dummy_intr(caddr_t arg);
53 static	int	 ghd_poll(ccc_t *cccp, gpoll_t polltype, ulong_t polltime,
54 			gcmd_t *poll_gcmdp, gtgt_t *gtgtp, void *intr_status);
55 
56 
57 /*
58  * Local configuration variables
59  */
60 
61 ulong_t	ghd_tran_abort_timeout = 5;
62 ulong_t	ghd_tran_abort_lun_timeout = 5;
63 ulong_t	ghd_tran_reset_target_timeout = 5;
64 ulong_t	ghd_tran_reset_bus_timeout = 5;
65 
66 static int
67 ghd_doneq_init(ccc_t *cccp)
68 {
69 	ddi_iblock_cookie_t iblock;
70 
71 	L2_INIT(&cccp->ccc_doneq);
72 	cccp->ccc_hba_pollmode = TRUE;
73 
74 	if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
75 	    &cccp->ccc_doneq_softid, &iblock, NULL,
76 	    ghd_doneq_process, (caddr_t)cccp) != DDI_SUCCESS) {
77 		GDBG_ERROR(("ghd_doneq_init: add softintr failed cccp 0x%p\n",
78 		    (void *)cccp));
79 		return (FALSE);
80 	}
81 
82 	mutex_init(&cccp->ccc_doneq_mutex, NULL, MUTEX_DRIVER, iblock);
83 	ghd_doneq_pollmode_exit(cccp);
84 	return (TRUE);
85 }
86 
87 /*
88  * ghd_complete():
89  *
90  *	The HBA driver calls this entry point when it's completely
91  *	done processing a request.
92  *
93  *	See the GHD_COMPLETE_INLINE() macro in ghd.h for the actual code.
94  */
95 
96 void
97 ghd_complete(ccc_t *cccp, gcmd_t *gcmdp)
98 {
99 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
100 	GHD_COMPLETE_INLINE(cccp, gcmdp);
101 }
102 
103 
104 /*
105  * ghd_doneq_put_head():
106  *
107  *	Mark the request done and prepend it to the doneq.
108  *	See the GHD_DONEQ_PUT_HEAD_INLINE() macros in ghd.h for
109  *	the actual code.
110  */
111 void
112 ghd_doneq_put_head(ccc_t *cccp, gcmd_t *gcmdp)
113 {
114 	GHD_DONEQ_PUT_HEAD_INLINE(cccp, gcmdp)
115 }
116 
117 /*
118  * ghd_doneq_put_tail():
119  *
120  *	Mark the request done and append it to the doneq.
121  *	See the GHD_DONEQ_PUT_TAIL_INLINE() macros in ghd.h for
122  *	the actual code.
123  */
124 void
125 ghd_doneq_put_tail(ccc_t *cccp, gcmd_t *gcmdp)
126 {
127 	GHD_DONEQ_PUT_TAIL_INLINE(cccp, gcmdp)
128 }
129 
130 static gcmd_t	*
131 ghd_doneq_get(ccc_t *cccp)
132 {
133 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
134 	gcmd_t	 *gcmdp;
135 
136 	mutex_enter(doneq_mutexp);
137 	if ((gcmdp = L2_next(&cccp->ccc_doneq)) != NULL)
138 		L2_delete(&gcmdp->cmd_q);
139 	mutex_exit(doneq_mutexp);
140 	return (gcmdp);
141 }
142 
143 
144 static void
145 ghd_doneq_pollmode_enter(ccc_t *cccp)
146 {
147 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
148 
149 	mutex_enter(doneq_mutexp);
150 	cccp->ccc_hba_pollmode = TRUE;
151 	mutex_exit(doneq_mutexp);
152 }
153 
154 
155 static void
156 ghd_doneq_pollmode_exit(ccc_t *cccp)
157 {
158 	kmutex_t *doneq_mutexp = &cccp->ccc_doneq_mutex;
159 
160 	mutex_enter(doneq_mutexp);
161 	cccp->ccc_hba_pollmode = FALSE;
162 	mutex_exit(doneq_mutexp);
163 
164 	/* trigger software interrupt for the completion callbacks */
165 	if (!L2_EMPTY(&cccp->ccc_doneq))
166 		ddi_trigger_softintr(cccp->ccc_doneq_softid);
167 }
168 
169 
170 /* ***************************************************************** */
171 
172 /*
173  *
174  * ghd_doneq_process()
175  *
176  *	This function is called directly from the software interrupt
177  *	handler.
178  *
179  *	The doneq is protected by a separate mutex than the
180  *	HBA mutex in order to avoid mutex contention on MP systems.
181  *
182  */
183 
184 static uint_t
185 ghd_doneq_process(caddr_t arg)
186 {
187 	ccc_t *cccp =	(ccc_t *)arg;
188 	kmutex_t	*doneq_mutexp;
189 	gcmd_t		*gcmdp;
190 	int			rc = DDI_INTR_UNCLAIMED;
191 
192 	doneq_mutexp = &cccp->ccc_doneq_mutex;
193 
194 	for (;;) {
195 		mutex_enter(doneq_mutexp);
196 		/* skip if FLAG_NOINTR request in progress */
197 		if (cccp->ccc_hba_pollmode)
198 			break;
199 		/* pop the first one from the done Q */
200 		if ((gcmdp = L2_next(&cccp->ccc_doneq)) == NULL)
201 			break;
202 		L2_delete(&gcmdp->cmd_q);
203 
204 		if (gcmdp->cmd_flags & GCMDFLG_RESET_NOTIFY) {
205 			/* special request; processed here and discarded */
206 			ghd_do_reset_notify_callbacks(cccp);
207 			ghd_gcmd_free(gcmdp);
208 			mutex_exit(doneq_mutexp);
209 			continue;
210 		}
211 
212 		/*
213 		 * drop the mutex since completion
214 		 * function can re-enter the top half via
215 		 * ghd_transport()
216 		 */
217 		mutex_exit(doneq_mutexp);
218 		gcmdp->cmd_state = GCMD_STATE_IDLE;
219 		(*cccp->ccc_hba_complete)(cccp->ccc_hba_handle, gcmdp, TRUE);
220 #ifdef notyet
221 		/* I don't think this is ever necessary */
222 		rc = DDI_INTR_CLAIMED;
223 #endif
224 	}
225 	mutex_exit(doneq_mutexp);
226 	return (rc);
227 }
228 
229 static void
230 ghd_do_reset_notify_callbacks(ccc_t *cccp)
231 {
232 	ghd_reset_notify_list_t *rnp;
233 	L2el_t *rnl = &cccp->ccc_reset_notify_list;
234 
235 	ASSERT(mutex_owned(&cccp->ccc_doneq_mutex));
236 
237 	/* lock the reset notify list while we operate on it */
238 	mutex_enter(&cccp->ccc_reset_notify_mutex);
239 
240 	for (rnp = (ghd_reset_notify_list_t *)L2_next(rnl);
241 	    rnp != NULL;
242 	    rnp = (ghd_reset_notify_list_t *)L2_next(&rnp->l2_link)) {
243 
244 		/* don't call if HBA driver didn't set it */
245 		if (cccp->ccc_hba_reset_notify_callback) {
246 			(*cccp->ccc_hba_reset_notify_callback)(rnp->gtgtp,
247 			    rnp->callback, rnp->arg);
248 		}
249 	}
250 	mutex_exit(&cccp->ccc_reset_notify_mutex);
251 }
252 
253 
254 /* ***************************************************************** */
255 
256 
257 
258 /*
259  * Autovector Interrupt Entry Point
260  *
261  *	Dummy return to be used before mutexes has been initialized
262  *	guard against interrupts from drivers sharing the same irq line
263  */
264 
265 /*ARGSUSED*/
266 static uint_t
267 ghd_dummy_intr(caddr_t arg)
268 {
269 	return (DDI_INTR_UNCLAIMED);
270 }
271 
272 
273 /*
274  * ghd_register()
275  *
276  *	Do the usual interrupt handler setup stuff.
277  *
278  *	Also, set up three mutexes: the wait queue mutex, the HBA
279  *	mutex, and the done queue mutex. The permitted locking
280  *	orders are:
281  *
282  *		1. enter(waitq)
283  *		2. enter(activel)
284  *		3. enter(doneq)
285  *		4. enter(HBA) then enter(activel)
286  *		5. enter(HBA) then enter(doneq)
287  *		6. enter(HBA) then enter(waitq)
288  *		7. enter(waitq) then tryenter(HBA)
289  *
290  *	Note: cases 6 and 7 won't deadlock because case 7 is always
291  *	mutex_tryenter() call.
292  *
293  */
294 
295 
296 int
297 ghd_register(char *labelp,
298 	ccc_t	*cccp,
299 	dev_info_t *dip,
300 	int	inumber,
301 	void	*hba_handle,
302 	int	(*ccballoc)(gtgt_t *, gcmd_t *, int, int, int, int),
303 	void	(*ccbfree)(gcmd_t *),
304 	void	(*sg_func)(gcmd_t *, ddi_dma_cookie_t *, int, int),
305 	int	(*hba_start)(void *, gcmd_t *),
306 	void    (*hba_complete)(void *, gcmd_t *, int),
307 	uint_t	(*int_handler)(caddr_t),
308 	int	(*get_status)(void *, void *),
309 	void	(*process_intr)(void *, void *),
310 	int	(*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int),
311 	tmr_t	*tmrp,
312 	void 	(*hba_reset_notify_callback)(gtgt_t *,
313 			void (*)(caddr_t), caddr_t))
314 {
315 
316 	cccp->ccc_label = labelp;
317 	cccp->ccc_hba_dip = dip;
318 	cccp->ccc_ccballoc = ccballoc;
319 	cccp->ccc_ccbfree = ccbfree;
320 	cccp->ccc_sg_func = sg_func;
321 	cccp->ccc_hba_start = hba_start;
322 	cccp->ccc_hba_complete = hba_complete;
323 	cccp->ccc_process_intr = process_intr;
324 	cccp->ccc_get_status = get_status;
325 	cccp->ccc_hba_handle = hba_handle;
326 	cccp->ccc_hba_reset_notify_callback = hba_reset_notify_callback;
327 
328 	/* initialize the HBA's list headers */
329 	CCCP_INIT(cccp);
330 
331 	/*
332 	 *	Establish initial dummy interrupt handler
333 	 *	get iblock cookie to initialize mutexes used in the
334 	 *	real interrupt handler
335 	 */
336 	if (ddi_add_intr(dip, inumber, &cccp->ccc_iblock, NULL,
337 	    ghd_dummy_intr, hba_handle) != DDI_SUCCESS) {
338 		return (FALSE);
339 	}
340 	mutex_init(&cccp->ccc_hba_mutex, NULL, MUTEX_DRIVER, cccp->ccc_iblock);
341 	ddi_remove_intr(dip, inumber, cccp->ccc_iblock);
342 
343 	/* Establish real interrupt handler */
344 	if (ddi_add_intr(dip, inumber, &cccp->ccc_iblock, NULL,
345 	    int_handler, (caddr_t)hba_handle) != DDI_SUCCESS) {
346 		mutex_destroy(&cccp->ccc_hba_mutex);
347 		return (FALSE);
348 	}
349 
350 	mutex_init(&cccp->ccc_waitq_mutex, NULL,
351 	    MUTEX_DRIVER, cccp->ccc_iblock);
352 
353 	mutex_init(&cccp->ccc_reset_notify_mutex, NULL,
354 	    MUTEX_DRIVER, cccp->ccc_iblock);
355 
356 	if (ghd_timer_attach(cccp, tmrp, timeout_func) == FALSE) {
357 		ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
358 		mutex_destroy(&cccp->ccc_hba_mutex);
359 		mutex_destroy(&cccp->ccc_waitq_mutex);
360 		return (FALSE);
361 	}
362 
363 	if (ghd_doneq_init(cccp)) {
364 		return (TRUE);
365 	}
366 
367 	ghd_timer_detach(cccp);
368 	ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
369 	mutex_destroy(&cccp->ccc_hba_mutex);
370 	mutex_destroy(&cccp->ccc_waitq_mutex);
371 	return (FALSE);
372 
373 }
374 
375 
376 void
377 ghd_unregister(ccc_t *cccp)
378 {
379 	ghd_timer_detach(cccp);
380 	ddi_remove_intr(cccp->ccc_hba_dip, 0, cccp->ccc_iblock);
381 	ddi_remove_softintr(cccp->ccc_doneq_softid);
382 	mutex_destroy(&cccp->ccc_hba_mutex);
383 	mutex_destroy(&cccp->ccc_waitq_mutex);
384 	mutex_destroy(&cccp->ccc_doneq_mutex);
385 }
386 
387 
388 
389 int
390 ghd_intr(ccc_t *cccp, void *intr_status)
391 {
392 	int (*statfunc)(void *, void *) = cccp->ccc_get_status;
393 	void (*processfunc)(void *, void *) = cccp->ccc_process_intr;
394 	kmutex_t *waitq_mutexp = &cccp->ccc_waitq_mutex;
395 	kmutex_t *hba_mutexp = &cccp->ccc_hba_mutex;
396 	void		  *handle = cccp->ccc_hba_handle;
397 	int		   rc = DDI_INTR_UNCLAIMED;
398 	int		   more;
399 
400 
401 	mutex_enter(hba_mutexp);
402 
403 	GDBG_INTR(("ghd_intr(): cccp=0x%p status=0x%p\n",
404 		cccp, intr_status));
405 
406 	for (;;) {
407 		more = FALSE;
408 
409 		/* process the interrupt status */
410 		while ((*statfunc)(handle, intr_status)) {
411 			(*processfunc)(handle, intr_status);
412 			rc = DDI_INTR_CLAIMED;
413 			more = TRUE;
414 		}
415 		mutex_enter(waitq_mutexp);
416 		if (ghd_waitq_process_and_mutex_hold(cccp)) {
417 			ASSERT(mutex_owned(hba_mutexp));
418 			mutex_exit(waitq_mutexp);
419 			continue;
420 		}
421 		if (more) {
422 			mutex_exit(waitq_mutexp);
423 			continue;
424 		}
425 		GDBG_INTR(("ghd_intr(): done cccp=0x%p status=0x%p rc %d\n",
426 			cccp, intr_status, rc));
427 		/*
428 		 * Release the mutexes in the opposite order that they
429 		 * were acquired to prevent requests queued by
430 		 * ghd_transport() from getting hung up in the wait queue.
431 		 */
432 		mutex_exit(hba_mutexp);
433 		mutex_exit(waitq_mutexp);
434 		return (rc);
435 	}
436 }
437 
438 static int
439 ghd_poll(ccc_t	*cccp,
440 	gpoll_t	 polltype,
441 	ulong_t	 polltime,
442 	gcmd_t	*poll_gcmdp,
443 	gtgt_t	*gtgtp,
444 	void	*intr_status)
445 {
446 	gcmd_t	*gcmdp;
447 	L2el_t	 gcmd_hold_queue;
448 	int	 got_it = FALSE;
449 	clock_t	 start_lbolt;
450 	clock_t	 current_lbolt;
451 
452 
453 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
454 	L2_INIT(&gcmd_hold_queue);
455 
456 	/* Que hora es? */
457 	start_lbolt = ddi_get_lbolt();
458 
459 	/* unqueue and save all CMD/CCBs until I find the right one */
460 	while (!got_it) {
461 
462 		/* Give up yet? */
463 		current_lbolt = ddi_get_lbolt();
464 		if (polltime && (current_lbolt - start_lbolt >= polltime))
465 			break;
466 
467 		/*
468 		 * delay 1 msec each time around the loop (this is an
469 		 * arbitrary delay value, any value should work) except
470 		 * zero because some devices don't like being polled too
471 		 * fast and it saturates the bus on an MP system.
472 		 */
473 		drv_usecwait(1000);
474 
475 		/*
476 		 * check for any new device status
477 		 */
478 		if ((*cccp->ccc_get_status)(cccp->ccc_hba_handle, intr_status))
479 			(*cccp->ccc_process_intr)(cccp->ccc_hba_handle,
480 			    intr_status);
481 
482 		/*
483 		 * If something completed then try to start the
484 		 * next request from the wait queue. Don't release
485 		 * the HBA mutex because I don't know whether my
486 		 * request(s) is/are on the done queue yet.
487 		 */
488 		mutex_enter(&cccp->ccc_waitq_mutex);
489 		(void) ghd_waitq_process_and_mutex_hold(cccp);
490 		mutex_exit(&cccp->ccc_waitq_mutex);
491 
492 		/*
493 		 * Process the first of any timed-out requests.
494 		 */
495 		ghd_timer_poll(cccp, GHD_TIMER_POLL_ONE);
496 
497 		/*
498 		 * Unqueue all the completed requests, look for mine
499 		 */
500 		while (gcmdp = ghd_doneq_get(cccp)) {
501 			/*
502 			 * If we got one and it's my request, then
503 			 * we're done.
504 			 */
505 			if (gcmdp == poll_gcmdp) {
506 				poll_gcmdp->cmd_state = GCMD_STATE_IDLE;
507 				got_it = TRUE;
508 				continue;
509 			}
510 			/* fifo queue the other cmds on my local list */
511 			L2_add(&gcmd_hold_queue, &gcmdp->cmd_q, gcmdp);
512 		}
513 
514 
515 		/*
516 		 * Check whether we're done yet.
517 		 */
518 		switch (polltype) {
519 		case GHD_POLL_DEVICE:
520 			/*
521 			 * wait for everything queued on a specific device
522 			 */
523 			if (GDEV_NACTIVE(gtgtp->gt_gdevp) == 0)
524 				got_it = TRUE;
525 			break;
526 
527 		case GHD_POLL_ALL:
528 			/*
529 			 * if waiting for all outstanding requests and
530 			 * if active list is now empty then exit
531 			 */
532 			if (GHBA_NACTIVE(cccp) == 0)
533 				got_it = TRUE;
534 			break;
535 
536 		case GHD_POLL_REQUEST:
537 			break;
538 
539 		}
540 	}
541 
542 	if (L2_EMPTY(&gcmd_hold_queue)) {
543 		ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
544 		ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
545 		return (got_it);
546 	}
547 
548 	/*
549 	 * copy the local gcmd_hold_queue back to the doneq so
550 	 * that the order of completion callbacks is preserved
551 	 */
552 	while (gcmdp = L2_next(&gcmd_hold_queue)) {
553 		L2_delete(&gcmdp->cmd_q);
554 		GHD_DONEQ_PUT_TAIL(cccp, gcmdp);
555 	}
556 
557 	ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
558 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
559 	return (got_it);
560 }
561 
562 
563 /*
564  * ghd_tran_abort()
565  *
566  *	Abort specific command on a target.
567  *
568  */
569 
570 int
571 ghd_tran_abort(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp, void *intr_status)
572 {
573 	gact_t	 action;
574 	int	 rc;
575 
576 	/*
577 	 * call the driver's abort_cmd function
578 	 */
579 
580 	mutex_enter(&cccp->ccc_hba_mutex);
581 	ghd_doneq_pollmode_enter(cccp);
582 
583 	switch (gcmdp->cmd_state) {
584 	case GCMD_STATE_WAITQ:
585 		/* not yet started */
586 		action = GACTION_EARLY_ABORT;
587 		break;
588 
589 	case GCMD_STATE_ACTIVE:
590 		/* in progress */
591 		action = GACTION_ABORT_CMD;
592 		break;
593 
594 	default:
595 		/* everything else, probably already being aborted */
596 		rc = FALSE;
597 		goto exit;
598 	}
599 
600 	/* stop the timer and remove it from the active list */
601 	GHD_TIMER_STOP(cccp, gcmdp);
602 
603 	/* start a new timer and send out the abort command */
604 	ghd_timer_newstate(cccp, gcmdp, gtgtp, action, GHD_TGTREQ);
605 
606 	/* wait for the abort to complete */
607 	if (rc = ghd_poll(cccp, GHD_POLL_REQUEST, ghd_tran_abort_timeout,
608 	    gcmdp, gtgtp, intr_status)) {
609 		gcmdp->cmd_state = GCMD_STATE_DONEQ;
610 		GHD_DONEQ_PUT_TAIL(cccp, gcmdp);
611 	}
612 
613 exit:
614 	ghd_doneq_pollmode_exit(cccp);
615 
616 	mutex_enter(&cccp->ccc_waitq_mutex);
617 	ghd_waitq_process_and_mutex_exit(cccp);
618 
619 	return (rc);
620 }
621 
622 
623 /*
624  * ghd_tran_abort_lun()
625  *
626  *	Abort all commands on a specific target.
627  *
628  */
629 
630 int
631 ghd_tran_abort_lun(ccc_t *cccp,	gtgt_t *gtgtp, void *intr_status)
632 {
633 	int	 rc;
634 
635 	/*
636 	 * call the HBA driver's abort_device function
637 	 */
638 
639 	mutex_enter(&cccp->ccc_hba_mutex);
640 	ghd_doneq_pollmode_enter(cccp);
641 
642 	/* send out the abort device request */
643 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_ABORT_DEV, GHD_TGTREQ);
644 
645 	/* wait for the device to go idle */
646 	rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_abort_lun_timeout,
647 		NULL, gtgtp, intr_status);
648 
649 	ghd_doneq_pollmode_exit(cccp);
650 
651 	mutex_enter(&cccp->ccc_waitq_mutex);
652 	ghd_waitq_process_and_mutex_exit(cccp);
653 
654 	return (rc);
655 }
656 
657 
658 
659 /*
660  * ghd_tran_reset_target()
661  *
662  *	reset the target device
663  *
664  *
665  */
666 
667 int
668 ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status)
669 {
670 	int rc = TRUE;
671 
672 
673 	mutex_enter(&cccp->ccc_hba_mutex);
674 	ghd_doneq_pollmode_enter(cccp);
675 
676 	/* send out the device reset request */
677 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_TARGET, GHD_TGTREQ);
678 
679 	/* wait for the device to reset */
680 	rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_reset_target_timeout,
681 		NULL, gtgtp, intr_status);
682 
683 	ghd_doneq_pollmode_exit(cccp);
684 
685 	mutex_enter(&cccp->ccc_waitq_mutex);
686 	ghd_waitq_process_and_mutex_exit(cccp);
687 
688 	return (rc);
689 }
690 
691 
692 
693 /*
694  * ghd_tran_reset_bus()
695  *
696  *	reset the scsi bus
697  *
698  */
699 
700 int
701 ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status)
702 {
703 	int	rc;
704 
705 	mutex_enter(&cccp->ccc_hba_mutex);
706 	ghd_doneq_pollmode_enter(cccp);
707 
708 	/* send out the bus reset request */
709 	ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_BUS, GHD_TGTREQ);
710 
711 	/*
712 	 * Wait for all active requests on this HBA to complete
713 	 */
714 	rc = ghd_poll(cccp, GHD_POLL_ALL, ghd_tran_reset_bus_timeout,
715 		NULL, NULL, intr_status);
716 
717 
718 	ghd_doneq_pollmode_exit(cccp);
719 
720 	mutex_enter(&cccp->ccc_waitq_mutex);
721 	ghd_waitq_process_and_mutex_exit(cccp);
722 
723 	return (rc);
724 }
725 
726 
727 int
728 ghd_transport(ccc_t	*cccp,
729 		gcmd_t	*gcmdp,
730 		gtgt_t	*gtgtp,
731 		ulong_t	 timeout,
732 		int	 polled,
733 		void	*intr_status)
734 {
735 	gdev_t	*gdevp = gtgtp->gt_gdevp;
736 
737 	ASSERT(!mutex_owned(&cccp->ccc_hba_mutex));
738 	ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
739 
740 	if (polled) {
741 		/*
742 		 * Grab the HBA mutex so no other requests are started
743 		 * until after this one completes.
744 		 */
745 		mutex_enter(&cccp->ccc_hba_mutex);
746 
747 		GDBG_START(("ghd_transport: polled"
748 			" cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n",
749 				cccp, gdevp, gtgtp, gcmdp));
750 
751 		/*
752 		 * Lock the doneq so no other thread flushes the Q.
753 		 */
754 		ghd_doneq_pollmode_enter(cccp);
755 	}
756 #if defined(GHD_DEBUG) || defined(__lint)
757 	else {
758 		GDBG_START(("ghd_transport: non-polled"
759 			" cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n",
760 				cccp, gdevp, gtgtp, gcmdp));
761 	}
762 #endif
763 	/*
764 	 * add this request to the tail of the waitq
765 	 */
766 	gcmdp->cmd_waitq_level = 1;
767 	mutex_enter(&cccp->ccc_waitq_mutex);
768 	L2_add(&GDEV_QHEAD(gdevp), &gcmdp->cmd_q, gcmdp);
769 
770 	/*
771 	 * Add this request to the packet timer active list and start its
772 	 * abort timer.
773 	 */
774 	gcmdp->cmd_state = GCMD_STATE_WAITQ;
775 	ghd_timer_start(cccp, gcmdp, timeout);
776 
777 
778 	/*
779 	 * Check the device wait queue throttle and perhaps move
780 	 * some requests to the end of the HBA wait queue.
781 	 */
782 	ghd_waitq_shuffle_up(cccp, gdevp);
783 
784 	if (!polled) {
785 		/*
786 		 * See if the HBA mutex is available but use the
787 		 * tryenter so I don't deadlock.
788 		 */
789 		if (!mutex_tryenter(&cccp->ccc_hba_mutex)) {
790 			/* The HBA mutex isn't available */
791 			GDBG_START(("ghd_transport: !mutex cccp 0x%p\n", cccp));
792 			mutex_exit(&cccp->ccc_waitq_mutex);
793 			return (TRAN_ACCEPT);
794 		}
795 		GDBG_START(("ghd_transport: got mutex cccp 0x%p\n", cccp));
796 
797 		/*
798 		 * start as many requests as possible from the head
799 		 * of the HBA wait queue
800 		 */
801 
802 		ghd_waitq_process_and_mutex_exit(cccp);
803 
804 		ASSERT(!mutex_owned(&cccp->ccc_hba_mutex));
805 		ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
806 
807 		return (TRAN_ACCEPT);
808 	}
809 
810 
811 	/*
812 	 * If polled mode (FLAG_NOINTR specified in scsi_pkt flags),
813 	 * then ghd_poll() waits until the request completes or times out
814 	 * before returning.
815 	 */
816 
817 	mutex_exit(&cccp->ccc_waitq_mutex);
818 	(void) ghd_poll(cccp, GHD_POLL_REQUEST, 0, gcmdp, gtgtp, intr_status);
819 	ghd_doneq_pollmode_exit(cccp);
820 
821 	mutex_enter(&cccp->ccc_waitq_mutex);
822 	ghd_waitq_process_and_mutex_exit(cccp);
823 
824 	/* call HBA's completion function but don't do callback to target */
825 	(*cccp->ccc_hba_complete)(cccp->ccc_hba_handle, gcmdp, FALSE);
826 
827 	GDBG_START(("ghd_transport: polled done cccp 0x%p\n", cccp));
828 	return (TRAN_ACCEPT);
829 }
830 
831 int ghd_reset_notify(ccc_t 	*cccp,
832 			gtgt_t *gtgtp,
833 			int 	flag,
834 			void 	(*callback)(caddr_t),
835 			caddr_t arg)
836 {
837 	ghd_reset_notify_list_t *rnp;
838 	int rc = FALSE;
839 
840 	switch (flag) {
841 
842 	case SCSI_RESET_NOTIFY:
843 
844 		rnp = (ghd_reset_notify_list_t *)kmem_zalloc(sizeof (*rnp),
845 		    KM_SLEEP);
846 		rnp->gtgtp = gtgtp;
847 		rnp->callback = callback;
848 		rnp->arg = arg;
849 
850 		mutex_enter(&cccp->ccc_reset_notify_mutex);
851 		L2_add(&cccp->ccc_reset_notify_list, &rnp->l2_link,
852 		    (void *)rnp);
853 		mutex_exit(&cccp->ccc_reset_notify_mutex);
854 
855 		rc = TRUE;
856 
857 		break;
858 
859 	case SCSI_RESET_CANCEL:
860 
861 		mutex_enter(&cccp->ccc_reset_notify_mutex);
862 		for (rnp = (ghd_reset_notify_list_t *)
863 			L2_next(&cccp->ccc_reset_notify_list);
864 		    rnp != NULL;
865 		    rnp = (ghd_reset_notify_list_t *)L2_next(&rnp->l2_link)) {
866 			if (rnp->gtgtp == gtgtp &&
867 			    rnp->callback == callback &&
868 			    rnp->arg == arg) {
869 				L2_delete(&rnp->l2_link);
870 				kmem_free(rnp, sizeof (*rnp));
871 				rc = TRUE;
872 			}
873 		}
874 		mutex_exit(&cccp->ccc_reset_notify_mutex);
875 		break;
876 
877 	default:
878 		rc = FALSE;
879 		break;
880 	}
881 
882 	return (rc);
883 }
884 
885 /*
886  * freeze the HBA waitq output (see ghd_waitq_process_and_mutex_hold),
887  * presumably because of a SCSI reset, for delay milliseconds.
888  */
889 
890 void
891 ghd_freeze_waitq(ccc_t *cccp, int delay)
892 {
893 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
894 
895 	/* freeze the waitq for delay milliseconds */
896 
897 	mutex_enter(&cccp->ccc_waitq_mutex);
898 	cccp->ccc_waitq_freezetime = ddi_get_lbolt();
899 	cccp->ccc_waitq_freezedelay = delay;
900 	cccp->ccc_waitq_frozen = 1;
901 	mutex_exit(&cccp->ccc_waitq_mutex);
902 }
903 
904 void
905 ghd_queue_hold(ccc_t *cccp)
906 {
907 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
908 
909 	mutex_enter(&cccp->ccc_waitq_mutex);
910 	cccp->ccc_waitq_held = 1;
911 	mutex_exit(&cccp->ccc_waitq_mutex);
912 }
913 
914 void
915 ghd_queue_unhold(ccc_t *cccp)
916 {
917 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
918 
919 	mutex_enter(&cccp->ccc_waitq_mutex);
920 	cccp->ccc_waitq_held = 0;
921 	mutex_exit(&cccp->ccc_waitq_mutex);
922 }
923 
924 
925 
926 /*
927  * Trigger previously-registered reset notifications
928  */
929 
930 void
931 ghd_trigger_reset_notify(ccc_t *cccp)
932 {
933 	gcmd_t *gcmdp;
934 
935 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
936 
937 	/* create magic doneq entry */
938 
939 	gcmdp = ghd_gcmd_alloc((gtgt_t *)NULL, 0, TRUE);
940 	gcmdp->cmd_flags = GCMDFLG_RESET_NOTIFY;
941 
942 	/* put at head of doneq so it's processed ASAP */
943 
944 	GHD_DONEQ_PUT_HEAD(cccp, gcmdp);
945 }
946