From 4977f49a15c933566f6912d44c2d3c9160f290a0 Mon Sep 17 00:00:00 2001 From: mjacob Date: Sun, 8 Feb 2004 19:17:56 +0000 Subject: Remove condition variables and status associated with target mode enabling. Instead, go to an interrupt/polled model. Fix get_lun_statep so we don't panic if there are no wildcard luns enabled. MFC after: 6 days --- sys/dev/isp/isp_freebsd.c | 415 +++++++++++++++++++--------------------------- 1 file changed, 169 insertions(+), 246 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 3ce3322..857b62d 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -201,12 +201,6 @@ isp_attach(struct ispsoftc *isp) isp->isp_path2 = path; } -#ifdef ISP_TARGET_MODE - cv_init(&isp->isp_osinfo.tgtcv0[0], "isp_tgcv0a"); - cv_init(&isp->isp_osinfo.tgtcv0[1], "isp_tgcv0b"); - cv_init(&isp->isp_osinfo.tgtcv1[0], "isp_tgcv1a"); - cv_init(&isp->isp_osinfo.tgtcv1[1], "isp_tgcv1b"); -#endif /* * Create device nodes */ @@ -538,15 +532,12 @@ static INLINE int is_lun_enabled(struct ispsoftc *, int, lun_id_t); static INLINE int are_any_luns_enabled(struct ispsoftc *, int); static INLINE tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t); static INLINE void rls_lun_statep(struct ispsoftc *, tstate_t *); -static INLINE int isp_psema_sig_rqe(struct ispsoftc *, int); -static INLINE int isp_cv_wait_timed_rqe(struct ispsoftc *, int, int); -static INLINE void isp_cv_signal_rqe(struct ispsoftc *, int, int); -static INLINE void isp_vsema_rqe(struct ispsoftc *, int); static INLINE atio_private_data_t *isp_get_atpd(struct ispsoftc *, int); static cam_status create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **); static void destroy_lun_state(struct ispsoftc *, tstate_t *); -static void isp_en_lun(struct ispsoftc *, union ccb *); +static int isp_en_lun(struct ispsoftc *, union ccb *); +static void isp_ledone(struct ispsoftc *, lun_entry_t *); static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); static timeout_t isp_refire_putback_atio; static void isp_complete_ctio(union ccb *); @@ -604,6 +595,7 @@ get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun) tptr->hold++; return (tptr); } + return (NULL); } else { tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; if (tptr == NULL) { @@ -627,74 +619,6 @@ rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) tptr->hold--; } -static INLINE int -isp_psema_sig_rqe(struct ispsoftc *isp, int bus) -{ - while (isp->isp_osinfo.tmflags[bus] & TM_BUSY) { - isp->isp_osinfo.tmflags[bus] |= TM_WANTED; -#ifdef ISP_SMPLOCK - if (cv_wait_sig(&isp->isp_osinfo.tgtcv0[bus], &isp->isp_lock)) { - return (-1); - } -#else - /* - * It's not allowed for us to use tsleep any more because - * a caller might have a non-sleepable lock held. - */ -#if 0 - if (tsleep(&isp->isp_osinfo.tgtcv0[bus], PZERO, "cv_isp", 0)) { - return (-1); - } -#else - return (-1); -#endif -#endif - isp->isp_osinfo.tmflags[bus] |= TM_BUSY; - } - return (0); -} - -static INLINE int -isp_cv_wait_timed_rqe(struct ispsoftc *isp, int bus, int timo) -{ -#ifdef ISP_SMPLOCK - if (cv_timedwait(&isp->isp_osinfo.tgtcv1[bus], &isp->isp_lock, timo)) { - return (-1); - } -#else - if (tsleep(&isp->isp_osinfo.tgtcv1[bus], PZERO, "cv_isp1", 0)) { - return (-1); - } -#endif - return (0); -} - -static INLINE void -isp_cv_signal_rqe(struct ispsoftc *isp, int bus, int status) -{ - isp->isp_osinfo.rstatus[bus] = status; -#ifdef ISP_SMPLOCK - cv_signal(&isp->isp_osinfo.tgtcv1[bus]); -#else - wakeup(&isp->isp_osinfo.tgtcv1[bus]); -#endif -} - -static INLINE void -isp_vsema_rqe(struct ispsoftc *isp, int bus) -{ - if (isp->isp_osinfo.tmflags[bus] & TM_WANTED) { - isp->isp_osinfo.tmflags[bus] &= ~TM_WANTED; -#ifdef ISP_SMPLOCK - cv_signal(&isp->isp_osinfo.tgtcv0[bus]); -#else - cv_signal(&isp->isp_osinfo.tgtcv0[bus]); - /* wakeup(&isp->isp_osinfo.tgtcv0[bus]); */ -#endif - } - isp->isp_osinfo.tmflags[bus] &= ~TM_BUSY; -} - static INLINE atio_private_data_t * isp_get_atpd(struct ispsoftc *isp, int tag) { @@ -759,10 +683,10 @@ destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) int hfx; tstate_t *lw, *pw; - hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); if (tptr->hold) { return; } + hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); pw = isp->isp_osinfo.lun_hash[hfx]; if (pw == NULL) { return; @@ -787,32 +711,37 @@ destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) } /* - * we enter with our locks held. + * Enable luns. */ -static void +static int isp_en_lun(struct ispsoftc *isp, union ccb *ccb) { - const char lfmt[] = "lun %d now %sabled for target mode on channel %d"; struct ccb_en_lun *cel = &ccb->cel; tstate_t *tptr; - u_int16_t rstat; + u_int32_t seq; int bus, cmd, av, wildcard, tm_on; lun_id_t lun; target_id_t tgt; - - bus = XS_CHANNEL(ccb) & 0x1; + bus = XS_CHANNEL(ccb); + if (bus > 1) { + xpt_print_path(ccb->ccb_h.path); + printf("illegal bus %d\n", bus); + ccb->ccb_h.status = CAM_PATH_INVALID; + return (-1); + } tgt = ccb->ccb_h.target_id; lun = ccb->ccb_h.target_lun; - /* - * Do some sanity checking first. - */ + isp_prt(isp, ISP_LOGTDEBUG0, + "isp_en_lun: %sabling lun 0x%x on channel %d", + cel->enable? "en" : "dis", lun, bus); + if ((lun != CAM_LUN_WILDCARD) && (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { ccb->ccb_h.status = CAM_LUN_INVALID; - return; + return (-1); } if (IS_SCSI(isp)) { @@ -821,7 +750,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) if (tgt != CAM_TARGET_WILDCARD && tgt != sdp->isp_initiator_id) { ccb->ccb_h.status = CAM_TID_INVALID; - return; + return (-1); } } else { /* @@ -832,7 +761,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) if (tgt != CAM_TARGET_WILDCARD && tgt != FCPARAM(isp)->isp_iid) { ccb->ccb_h.status = CAM_TID_INVALID; - return; + return (-1); } #endif /* @@ -842,7 +771,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) isp_prt(isp, ISP_LOGERR, "firmware does not support target mode"); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return; + return (-1); } /* * XXX: We *could* handle non-SCCLUN f/w, but we'd have to @@ -852,7 +781,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) isp_prt(isp, ISP_LOGERR, "firmware not SCCLUN capable"); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return; + return (-1); } } @@ -861,7 +790,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) wildcard = 1; } else { ccb->ccb_h.status = CAM_LUN_INVALID; - return; + return (-1); } } else { wildcard = 0; @@ -880,10 +809,9 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) if (wildcard) { tptr = &isp->isp_osinfo.tsdflt[bus]; if (cel->enable) { - if (isp->isp_osinfo.tmflags[bus] & - TM_WILDCARD_ENABLED) { + if (tm_on) { ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return; + return (-1); } ccb->ccb_h.status = xpt_create_path(&tptr->owner, NULL, @@ -891,20 +819,19 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) xpt_path_target_id(ccb->ccb_h.path), xpt_path_lun_id(ccb->ccb_h.path)); if (ccb->ccb_h.status != CAM_REQ_CMP) { - return; + return (-1); } SLIST_INIT(&tptr->atios); SLIST_INIT(&tptr->inots); isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; } else { - if ((isp->isp_osinfo.tmflags[bus] & - TM_WILDCARD_ENABLED) == 0) { + if (tm_on == 0) { ccb->ccb_h.status = CAM_REQ_CMP; - return; + return (-1); } if (tptr->hold) { ccb->ccb_h.status = CAM_SCSI_BUSY; - return; + return (-1); } xpt_free_path(tptr->owner); isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; @@ -926,7 +853,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) ~TM_WILDCARD_ENABLED; xpt_free_path(tptr->owner); } - return; + return (-1); } isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; isp_prt(isp, ISP_LOGINFO, @@ -934,12 +861,12 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) } else if (cel->enable == 0 && tm_on && wildcard) { if (are_any_luns_enabled(isp, bus)) { ccb->ccb_h.status = CAM_SCSI_BUSY; - return; + return (-1); } av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); if (av) { ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return; + return (-1); } isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; isp_prt(isp, ISP_LOGINFO, @@ -948,33 +875,40 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) if (wildcard) { ccb->ccb_h.status = CAM_REQ_CMP; - return; + return (-1); + } + + /* + * Find an empty slot + */ + for (seq = 0; seq < NLEACT; seq++) { + if (isp->isp_osinfo.leact[seq] == 0) { + break; + } } + if (seq >= NLEACT) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return (-1); + + } + isp->isp_osinfo.leact[seq] = ccb; if (cel->enable) { ccb->ccb_h.status = create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); if (ccb->ccb_h.status != CAM_REQ_CMP) { - return; + isp->isp_osinfo.leact[seq] = 0; + return (-1); } } else { tptr = get_lun_statep(isp, bus, lun); if (tptr == NULL) { ccb->ccb_h.status = CAM_LUN_INVALID; - return; + return (-1); } } - if (isp_psema_sig_rqe(isp, bus)) { - rls_lun_statep(isp, tptr); - if (cel->enable) - destroy_lun_state(isp, tptr); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - return; - } - if (cel->enable) { - u_int32_t seq = isp->isp_osinfo.rollinfo++; int c, n, ulun = lun; cmd = RQSTYPE_ENABLE_LUN; @@ -989,33 +923,15 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) */ ulun = 0; } - rstat = LUN_ERR; - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed"); - goto out; - } - if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, - "wait for ENABLE/MODIFY LUN timed out"); - goto out; - } - rstat = isp->isp_osinfo.rstatus[bus]; - if (rstat != LUN_OK) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, - "ENABLE/MODIFY LUN returned 0x%x", rstat); - goto out; + if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { + rls_lun_statep(isp, tptr); + ccb->ccb_h.status = CAM_REQ_INPROG; + return (seq); } } else { int c, n, ulun = lun; - u_int32_t seq; - rstat = LUN_ERR; - seq = isp->isp_osinfo.rollinfo++; cmd = -RQSTYPE_MODIFY_LUN; - c = DFLT_CMND_CNT; n = DFLT_INOT_CNT; if (IS_FC(isp) && lun != 0) { @@ -1026,86 +942,116 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb) */ ulun = 0; } - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); - goto out; - } - if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, - "wait for MODIFY LUN timed out"); - goto out; - } - rstat = isp->isp_osinfo.rstatus[bus]; - if (rstat != LUN_OK) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, - "MODIFY LUN returned 0x%x", rstat); - goto out; - } - if (IS_FC(isp) && lun) { - goto out; + if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { + rls_lun_statep(isp, tptr); + ccb->ccb_h.status = CAM_REQ_INPROG; + return (seq); } + } + rls_lun_statep(isp, tptr); + xpt_print_path(ccb->ccb_h.path); + printf("isp_lun_cmd failed\n"); + isp->isp_osinfo.leact[seq] = 0; + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + return (-1); +} - seq = isp->isp_osinfo.rollinfo++; +static void +isp_ledone(struct ispsoftc *isp, lun_entry_t *lep) +{ + const char lfmt[] = "lun %d now %sabled for target mode on channel %d"; + union ccb *ccb; + u_int32_t seq; + tstate_t *tptr; + int av; + struct ccb_en_lun *cel; - rstat = LUN_ERR; - cmd = -RQSTYPE_ENABLE_LUN; - if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); - goto out; - } - if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGERR, - "wait for DISABLE LUN timed out"); - goto out; - } - rstat = isp->isp_osinfo.rstatus[bus]; - if (rstat != LUN_OK) { - xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGWARN, - "DISABLE LUN returned 0x%x", rstat); - goto out; - } - if (are_any_luns_enabled(isp, bus) == 0) { - av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); - if (av) { - isp_prt(isp, ISP_LOGWARN, - "disable target mode on channel %d failed", - bus); - goto out; - } - isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; - isp_prt(isp, ISP_LOGINFO, - "Target Mode disabled on channel %d", bus); - } + seq = lep->le_reserved - 1; + if (seq >= NLEACT) { + isp_prt(isp, ISP_LOGERR, + "seq out of range (%u) in isp_ledone", seq); + return; + } + ccb = isp->isp_osinfo.leact[seq]; + if (ccb == 0) { + isp_prt(isp, ISP_LOGERR, + "no ccb for seq %u in isp_ledone", seq); + return; + } + cel = &ccb->cel; + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); + if (tptr == NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("null tptr in isp_ledone\n"); + isp->isp_osinfo.leact[seq] = 0; + return; } -out: - isp_vsema_rqe(isp, bus); - - if (rstat != LUN_OK) { + if (lep->le_status != LUN_OK) { xpt_print_path(ccb->ccb_h.path); - isp_prt(isp, ISP_LOGWARN, - "lun %sable failed", (cel->enable) ? "en" : "dis"); + printf("ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); +err: ccb->ccb_h.status = CAM_REQ_CMP_ERR; + xpt_print_path(ccb->ccb_h.path); rls_lun_statep(isp, tptr); - if (cel->enable) - destroy_lun_state(isp, tptr); + isp->isp_osinfo.leact[seq] = 0; + ISPLOCK_2_CAMLOCK(isp); + xpt_done(ccb); + CAMLOCK_2_ISPLOCK(isp); + return; } else { - isp_prt(isp, ISP_LOGINFO, lfmt, lun, - (cel->enable) ? "en" : "dis", bus); + isp_prt(isp, ISP_LOGTDEBUG0, + "isp_ledone: ENABLE/MODIFY done okay"); + } + + + if (cel->enable) { + ccb->ccb_h.status = CAM_REQ_CMP; + isp_prt(isp, /* ISP_LOGINFO */ ISP_LOGALL, lfmt, + XS_LUN(ccb), "en", XS_CHANNEL(ccb)); rls_lun_statep(isp, tptr); - if (cel->enable == 0) { - destroy_lun_state(isp, tptr); + isp->isp_osinfo.leact[seq] = 0; + ISPLOCK_2_CAMLOCK(isp); + xpt_done(ccb); + CAMLOCK_2_ISPLOCK(isp); + return; + } + + if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { + if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), + XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { + xpt_print_path(ccb->ccb_h.path); + printf("isp_ledone: isp_lun_cmd failed\n"); + goto err; } - ccb->ccb_h.status = CAM_REQ_CMP; + rls_lun_statep(isp, tptr); + return; + } + + isp_prt(isp, ISP_LOGINFO, lfmt, XS_LUN(ccb), "dis", XS_CHANNEL(ccb)); + rls_lun_statep(isp, tptr); + destroy_lun_state(isp, tptr); + ccb->ccb_h.status = CAM_REQ_CMP; + isp->isp_osinfo.leact[seq] = 0; + ISPLOCK_2_CAMLOCK(isp); + xpt_done(ccb); + CAMLOCK_2_ISPLOCK(isp); + if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { + int bus = XS_CHANNEL(ccb); + av = bus << 31; + av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); + if (av) { + isp_prt(isp, ISP_LOGWARN, + "disable target mode on channel %d failed", bus); + } else { + isp_prt(isp, ISP_LOGINFO, + "Target Mode disabled on channel %d", bus); + } + isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; } } + static cam_status isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) { @@ -1604,35 +1550,6 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) } } - if (tptr == NULL) { - /* - * What we'd like to know is whether or not we have a listener - * upstream that really hasn't configured yet. If we do, then - * we can give a more sensible reply here. If not, then we can - * reject this out of hand. - * - * Choices for what to send were - * - * Not Ready, Unit Not Self-Configured Yet - * (0x2,0x3e,0x00) - * - * for the former and - * - * Illegal Request, Logical Unit Not Supported - * (0x5,0x25,0x00) - * - * for the latter. - * - * We used to decide whether there was at least one listener - * based upon whether the black hole driver was configured. - * However, recent config(8) changes have made this hard to do - * at this time. - * - */ - isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); - return (0); - } - atp = isp_get_atpd(isp, 0); atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); if (atiop == NULL || atp == NULL) { @@ -1699,6 +1616,7 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) atp->last_xframt = 0; atp->bytes_xfered = 0; atp->state = ATPD_STATE_CAM; + ISPLOCK_2_CAMLOCK(siP); xpt_done((union ccb*)atiop); isp_prt(isp, ISP_LOGTDEBUG0, @@ -2216,14 +2134,26 @@ isp_action(struct cam_sim *sim, union ccb *ccb) #ifdef ISP_TARGET_MODE case XPT_EN_LUN: /* Enable LUN as a target */ { - int iok; + int seq, iok, i; CAMLOCK_2_ISPLOCK(isp); iok = isp->isp_osinfo.intsok; isp->isp_osinfo.intsok = 0; - isp_en_lun(isp, ccb); + seq = isp_en_lun(isp, ccb); + if (seq < 0) { + isp->isp_osinfo.intsok = iok; + ISPLOCK_2_CAMLOCK(isp); + xpt_done(ccb); + break; + } + for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { + u_int16_t isr, sema, mbox; + if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { + isp_intr(isp, isr, sema, mbox); + } + DELAY(1000); + } isp->isp_osinfo.intsok = iok; ISPLOCK_2_CAMLOCK(isp); - xpt_done(ccb); break; } case XPT_NOTIFY_ACK: /* recycle notify ack */ @@ -3122,14 +3052,7 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) break; case RQSTYPE_ENABLE_LUN: case RQSTYPE_MODIFY_LUN: - if (IS_DUALBUS(isp)) { - bus = - GET_BUS_VAL(((lun_entry_t *)arg)->le_rsvd); - } else { - bus = 0; - } - isp_cv_signal_rqe(isp, bus, - ((lun_entry_t *)arg)->le_status); + isp_ledone(isp, (lun_entry_t *) arg); break; } break; -- cgit v1.1