int ghd_tran_reset_bus(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status) { int rc; mutex_enter(&cccp->ccc_hba_mutex); ghd_doneq_pollmode_enter(cccp); /* send out the bus reset request */ ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_BUS, GHD_TGTREQ); /* * Wait for all active requests on this HBA to complete */ rc = ghd_poll(cccp, GHD_POLL_ALL, ghd_tran_reset_bus_timeout, NULL, NULL, intr_status); ghd_doneq_pollmode_exit(cccp); mutex_enter(&cccp->ccc_waitq_mutex); ghd_waitq_process_and_mutex_exit(cccp); return (rc); }
int ghd_tran_abort_lun(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status) { int rc; /* * call the HBA driver's abort_device function */ mutex_enter(&cccp->ccc_hba_mutex); ghd_doneq_pollmode_enter(cccp); /* send out the abort device request */ ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_ABORT_DEV, GHD_TGTREQ); /* wait for the device to go idle */ rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_abort_lun_timeout, NULL, gtgtp, intr_status); ghd_doneq_pollmode_exit(cccp); mutex_enter(&cccp->ccc_waitq_mutex); ghd_waitq_process_and_mutex_exit(cccp); return (rc); }
/*ARGSUSED*/ void ghd_target_free(dev_info_t *hba_dip, dev_info_t *tgt_dip, ccc_t *cccp, gtgt_t *gtgtp) { _NOTE(ARGUNUSED(hba_dip,tgt_dip)) gdev_t *gdevp = gtgtp->gt_gdevp; GDBG_WAITQ(("ghd_target_free(%d,%d) gdevp-0x%p gtgtp 0x%p\n", gtgtp->gt_target, gtgtp->gt_lun, (void *)gdevp, (void *)gtgtp)); /* * grab both mutexes so the queue structures * stay stable while deleting this instance */ mutex_enter(&cccp->ccc_hba_mutex); mutex_enter(&cccp->ccc_waitq_mutex); ASSERT(gdevp->gd_ninstances > 0); /* * remove this per-instance structure from the device list and * free the memory */ GTGT_DEATTACH(gtgtp, gdevp); kmem_free((caddr_t)gtgtp, gtgtp->gt_size); if (gdevp->gd_ninstances == 1) { GDBG_WAITQ(("ghd_target_free: N=1 gdevp 0x%p\n", (void *)gdevp)); /* * If there's now just one instance left attached to this * device then reset the queue's max active value * from that instance's saved value. */ gtgtp = GDEVP2GTGTP(gdevp); GDEV_MAXACTIVE(gdevp) = gtgtp->gt_maxactive; } else if (gdevp->gd_ninstances == 0) { /* else no instances left */ GDBG_WAITQ(("ghd_target_free: N=0 gdevp 0x%p\n", (void *)gdevp)); /* detach this per-dev-structure from the HBA's dev list */ GDEV_QDETACH(gdevp, cccp); kmem_free(gdevp, sizeof (*gdevp)); } #if defined(GHD_DEBUG) || defined(__lint) else { /* leave maxactive set to 1 */ GDBG_WAITQ(("ghd_target_free: N>1 gdevp 0x%p\n", (void *)gdevp)); } #endif ghd_waitq_process_and_mutex_exit(cccp); }
int ghd_tran_abort(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp, void *intr_status) { gact_t action; int rc; /* * call the driver's abort_cmd function */ mutex_enter(&cccp->ccc_hba_mutex); ghd_doneq_pollmode_enter(cccp); switch (gcmdp->cmd_state) { case GCMD_STATE_WAITQ: /* not yet started */ action = GACTION_EARLY_ABORT; break; case GCMD_STATE_ACTIVE: /* in progress */ action = GACTION_ABORT_CMD; break; default: /* everything else, probably already being aborted */ rc = FALSE; goto exit; } /* stop the timer and remove it from the active list */ GHD_TIMER_STOP(cccp, gcmdp); /* start a new timer and send out the abort command */ ghd_timer_newstate(cccp, gcmdp, gtgtp, action, GHD_TGTREQ); /* wait for the abort to complete */ if (rc = ghd_poll(cccp, GHD_POLL_REQUEST, ghd_tran_abort_timeout, gcmdp, gtgtp, intr_status)) { gcmdp->cmd_state = GCMD_STATE_DONEQ; GHD_DONEQ_PUT_TAIL(cccp, gcmdp); } exit: ghd_doneq_pollmode_exit(cccp); mutex_enter(&cccp->ccc_waitq_mutex); ghd_waitq_process_and_mutex_exit(cccp); return (rc); }
int ghd_tran_reset_target(ccc_t *cccp, gtgt_t *gtgtp, void *intr_status) { int rc = TRUE; mutex_enter(&cccp->ccc_hba_mutex); ghd_doneq_pollmode_enter(cccp); /* send out the device reset request */ ghd_timer_newstate(cccp, NULL, gtgtp, GACTION_RESET_TARGET, GHD_TGTREQ); /* wait for the device to reset */ rc = ghd_poll(cccp, GHD_POLL_DEVICE, ghd_tran_reset_target_timeout, NULL, gtgtp, intr_status); ghd_doneq_pollmode_exit(cccp); mutex_enter(&cccp->ccc_waitq_mutex); ghd_waitq_process_and_mutex_exit(cccp); return (rc); }
int ghd_transport(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp, ulong_t timeout, int polled, void *intr_status) { gdev_t *gdevp = gtgtp->gt_gdevp; ASSERT(!mutex_owned(&cccp->ccc_hba_mutex)); ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex)); if (polled) { /* * Grab the HBA mutex so no other requests are started * until after this one completes. */ mutex_enter(&cccp->ccc_hba_mutex); GDBG_START(("ghd_transport: polled" " cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n", (void *)cccp, (void *)gdevp, (void *)gtgtp, (void *)gcmdp)); /* * Lock the doneq so no other thread flushes the Q. */ ghd_doneq_pollmode_enter(cccp); } #if defined(GHD_DEBUG) || defined(__lint) else { GDBG_START(("ghd_transport: non-polled" " cccp 0x%p gdevp 0x%p gtgtp 0x%p gcmdp 0x%p\n", (void *)cccp, (void *)gdevp, (void *)gtgtp, (void *)gcmdp)); } #endif /* * add this request to the tail of the waitq */ gcmdp->cmd_waitq_level = 1; mutex_enter(&cccp->ccc_waitq_mutex); L2_add(&GDEV_QHEAD(gdevp), &gcmdp->cmd_q, gcmdp); /* * Add this request to the packet timer active list and start its * abort timer. */ gcmdp->cmd_state = GCMD_STATE_WAITQ; ghd_timer_start(cccp, gcmdp, timeout); /* * Check the device wait queue throttle and perhaps move * some requests to the end of the HBA wait queue. */ ghd_waitq_shuffle_up(cccp, gdevp); if (!polled) { /* * See if the HBA mutex is available but use the * tryenter so I don't deadlock. */ if (!mutex_tryenter(&cccp->ccc_hba_mutex)) { /* The HBA mutex isn't available */ GDBG_START(("ghd_transport: !mutex cccp 0x%p\n", (void *)cccp)); mutex_exit(&cccp->ccc_waitq_mutex); return (TRAN_ACCEPT); } GDBG_START(("ghd_transport: got mutex cccp 0x%p\n", (void *)cccp)); /* * start as many requests as possible from the head * of the HBA wait queue */ ghd_waitq_process_and_mutex_exit(cccp); ASSERT(!mutex_owned(&cccp->ccc_hba_mutex)); ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex)); return (TRAN_ACCEPT); } /* * If polled mode (FLAG_NOINTR specified in scsi_pkt flags), * then ghd_poll() waits until the request completes or times out * before returning. */ mutex_exit(&cccp->ccc_waitq_mutex); (void) ghd_poll(cccp, GHD_POLL_REQUEST, 0, gcmdp, gtgtp, intr_status); ghd_doneq_pollmode_exit(cccp); mutex_enter(&cccp->ccc_waitq_mutex); ghd_waitq_process_and_mutex_exit(cccp); /* call HBA's completion function but don't do callback to target */ (*cccp->ccc_hba_complete)(cccp->ccc_hba_handle, gcmdp, FALSE); GDBG_START(("ghd_transport: polled done cccp 0x%p\n", (void *)cccp)); return (TRAN_ACCEPT); }
/*ARGSUSED*/ gtgt_t * ghd_target_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, ccc_t *cccp, size_t tgt_private_size, void *hba_private, ushort_t target, uchar_t lun) { _NOTE(ARGUNUSED(hba_dip)) gtgt_t *gtgtp; size_t size = sizeof (*gtgtp) + tgt_private_size; gdev_t *gdevp; ulong_t maxactive; gtgtp = kmem_zalloc(size, KM_SLEEP); /* * initialize the per instance structure */ gtgtp->gt_tgt_private = (void *)(gtgtp + 1); gtgtp->gt_size = size; gtgtp->gt_hba_private = hba_private; gtgtp->gt_target = target; gtgtp->gt_lun = lun; gtgtp->gt_ccc = cccp; /* * set the queue's maxactive to 1 if * property not specified on target or hba devinfo node */ maxactive = ddi_getprop(DDI_DEV_T_ANY, tgt_dip, 0, "ghd-maxactive", 1); gtgtp->gt_maxactive = maxactive; /* initialize the linked list pointers */ GTGT_INIT(gtgtp); /* * grab both mutexes so the queue structures * stay stable while adding this instance to the linked lists */ mutex_enter(&cccp->ccc_hba_mutex); mutex_enter(&cccp->ccc_waitq_mutex); /* * Search the HBA's linked list of device structures. * * If this device is already attached then link this instance * to the existing per-device-structure on the ccc_devs list. * */ gdevp = CCCP2GDEVP(cccp); while (gdevp != NULL) { if (gdevp->gd_target == target && gdevp->gd_lun == lun) { GDBG_WAITQ(("ghd_target_init(%d,%d) found gdevp 0x%p" " gtgtp 0x%p max %lu\n", target, lun, gdevp, gtgtp, maxactive)); goto foundit; } gdevp = GDEV_NEXTP(gdevp); } /* * Not found. This is the first instance for this device. */ /* allocate the per-device-structure */ gdevp = kmem_zalloc(sizeof (*gdevp), KM_SLEEP); gdevp->gd_target = target; gdevp->gd_lun = lun; /* * link this second level queue to the HBA's first * level queue */ GDEV_QATTACH(gdevp, cccp, maxactive); GDBG_WAITQ(("ghd_target_init(%d,%d) new gdevp 0x%p gtgtp 0x%p" " max %lu\n", target, lun, gdevp, gtgtp, maxactive)); foundit: /* save the ptr to the per device structure */ gtgtp->gt_gdevp = gdevp; /* Add the per instance structure to the per device list */ GTGT_ATTACH(gtgtp, gdevp); ghd_waitq_process_and_mutex_exit(cccp); return (gtgtp); }