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
This commit is contained in:
Matt Jacob 2004-02-08 19:17:56 +00:00
parent c98d7aa472
commit 67ff51f150

View File

@ -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)) {
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;
}
if (lep->le_status != LUN_OK) {
xpt_print_path(ccb->ccb_h.path);
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);
isp->isp_osinfo.leact[seq] = 0;
ISPLOCK_2_CAMLOCK(isp);
xpt_done(ccb);
CAMLOCK_2_ISPLOCK(isp);
return;
} else {
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);
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);
isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed");
goto out;
printf("isp_ledone: isp_lun_cmd failed\n");
goto err;
}
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);
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 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;
"disable target mode on channel %d failed", bus);
} else {
isp_prt(isp, ISP_LOGINFO,
"Target Mode disabled on channel %d", bus);
}
}
out:
isp_vsema_rqe(isp, bus);
if (rstat != LUN_OK) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGWARN,
"lun %sable failed", (cel->enable) ? "en" : "dis");
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
rls_lun_statep(isp, tptr);
if (cel->enable)
destroy_lun_state(isp, tptr);
} else {
isp_prt(isp, ISP_LOGINFO, lfmt, lun,
(cel->enable) ? "en" : "dis", bus);
rls_lun_statep(isp, tptr);
if (cel->enable == 0) {
destroy_lun_state(isp, tptr);
}
ccb->ccb_h.status = CAM_REQ_CMP;
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;