int ghd_intr(ccc_t *cccp, void *intr_status) { int (*statfunc)(void *, void *) = cccp->ccc_get_status; void (*processfunc)(void *, void *) = cccp->ccc_process_intr; kmutex_t *waitq_mutexp = &cccp->ccc_waitq_mutex; kmutex_t *hba_mutexp = &cccp->ccc_hba_mutex; void *handle = cccp->ccc_hba_handle; int rc = DDI_INTR_UNCLAIMED; int more; mutex_enter(hba_mutexp); GDBG_INTR(("ghd_intr(): cccp=0x%p status=0x%p\n", (void *)cccp, intr_status)); for (;;) { more = FALSE; /* process the interrupt status */ while ((*statfunc)(handle, intr_status)) { (*processfunc)(handle, intr_status); rc = DDI_INTR_CLAIMED; more = TRUE; } mutex_enter(waitq_mutexp); if (ghd_waitq_process_and_mutex_hold(cccp)) { ASSERT(mutex_owned(hba_mutexp)); mutex_exit(waitq_mutexp); continue; } if (more) { mutex_exit(waitq_mutexp); continue; } GDBG_INTR(("ghd_intr(): done cccp=0x%p status=0x%p rc %d\n", (void *)cccp, intr_status, rc)); /* * Release the mutexes in the opposite order that they * were acquired to prevent requests queued by * ghd_transport() from getting hung up in the wait queue. */ mutex_exit(hba_mutexp); mutex_exit(waitq_mutexp); return (rc); } }
void ghd_waitq_process_and_mutex_exit(ccc_t *cccp) { ASSERT(mutex_owned(&cccp->ccc_hba_mutex)); ASSERT(mutex_owned(&cccp->ccc_waitq_mutex)); GDBG_WAITQ(("ghd_waitq_process_and_mutex_exit: cccp 0x%p\n", cccp)); (void) ghd_waitq_process_and_mutex_hold(cccp); /* * Release the mutexes in the opposite order that they * were acquired to prevent requests queued by * ghd_transport() from getting hung up in the wait queue. */ mutex_exit(&cccp->ccc_hba_mutex); mutex_exit(&cccp->ccc_waitq_mutex); }
static int ghd_poll(ccc_t *cccp, gpoll_t polltype, ulong_t polltime, gcmd_t *poll_gcmdp, gtgt_t *gtgtp, void *intr_status) { gcmd_t *gcmdp; L2el_t gcmd_hold_queue; int got_it = FALSE; clock_t poll_lbolt; clock_t start_lbolt; clock_t current_lbolt; ASSERT(mutex_owned(&cccp->ccc_hba_mutex)); L2_INIT(&gcmd_hold_queue); /* Que hora es? */ poll_lbolt = drv_usectohz((clock_t)polltime); start_lbolt = ddi_get_lbolt(); /* unqueue and save all CMD/CCBs until I find the right one */ while (!got_it) { /* Give up yet? */ current_lbolt = ddi_get_lbolt(); if (poll_lbolt && (current_lbolt - start_lbolt >= poll_lbolt)) break; /* * delay 1 msec each time around the loop (this is an * arbitrary delay value, any value should work) except * zero because some devices don't like being polled too * fast and it saturates the bus on an MP system. */ drv_usecwait(1000); /* * check for any new device status */ if ((*cccp->ccc_get_status)(cccp->ccc_hba_handle, intr_status)) (*cccp->ccc_process_intr)(cccp->ccc_hba_handle, intr_status); /* * If something completed then try to start the * next request from the wait queue. Don't release * the HBA mutex because I don't know whether my * request(s) is/are on the done queue yet. */ mutex_enter(&cccp->ccc_waitq_mutex); (void) ghd_waitq_process_and_mutex_hold(cccp); mutex_exit(&cccp->ccc_waitq_mutex); /* * Process the first of any timed-out requests. */ ghd_timer_poll(cccp, GHD_TIMER_POLL_ONE); /* * Unqueue all the completed requests, look for mine */ while (gcmdp = ghd_doneq_get(cccp)) { /* * If we got one and it's my request, then * we're done. */ if (gcmdp == poll_gcmdp) { poll_gcmdp->cmd_state = GCMD_STATE_IDLE; got_it = TRUE; continue; } /* fifo queue the other cmds on my local list */ L2_add(&gcmd_hold_queue, &gcmdp->cmd_q, gcmdp); } /* * Check whether we're done yet. */ switch (polltype) { case GHD_POLL_DEVICE: /* * wait for everything queued on a specific device */ if (GDEV_NACTIVE(gtgtp->gt_gdevp) == 0) got_it = TRUE; break; case GHD_POLL_ALL: /* * if waiting for all outstanding requests and * if active list is now empty then exit */ if (GHBA_NACTIVE(cccp) == 0) got_it = TRUE; break; case GHD_POLL_REQUEST: break; } } if (L2_EMPTY(&gcmd_hold_queue)) { ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex)); ASSERT(mutex_owned(&cccp->ccc_hba_mutex)); return (got_it); } /* * copy the local gcmd_hold_queue back to the doneq so * that the order of completion callbacks is preserved */ while (gcmdp = L2_next(&gcmd_hold_queue)) { L2_delete(&gcmdp->cmd_q); GHD_DONEQ_PUT_TAIL(cccp, gcmdp); } ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex)); ASSERT(mutex_owned(&cccp->ccc_hba_mutex)); return (got_it); }