summaryrefslogtreecommitdiffstats
path: root/sys/dev/isp/isp_freebsd.c
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2001-05-28 21:20:43 +0000
committermjacob <mjacob@FreeBSD.org>2001-05-28 21:20:43 +0000
commit19b20edd4063454edfe9d46a08ec2249527d1e8b (patch)
tree2ff029f1c3035ecb1a70ed1b7e80e5a0ed1b794c /sys/dev/isp/isp_freebsd.c
parentf80decdc0cdb69cc9099b1ba2b51651e287082f2 (diff)
downloadFreeBSD-src-19b20edd4063454edfe9d46a08ec2249527d1e8b.zip
FreeBSD-src-19b20edd4063454edfe9d46a08ec2249527d1e8b.tar.gz
Spring MegaChange #1.
---- Make a device for each ISP- really usable only with devfs and add an ioctl entry point (this can be used to (re)set debug levels, reset the HBA, rescan the fabric, issue lips, etc). ---- Add in a kernel thread for Fibre Channel cards. The purpose of this thread is to be woken up to clean up after Fibre Channel events block things. Basically, any FC event that casts doubt on the location or identify of FC devices blocks the queues. When, and if, we get the PORT DATABASE CHANGED or NAME SERVER DATABASE CHANGED async event, we activate the kthread which will then, in full thread context, re-evaluate the local loop and/or the fabric. When it's satisfied that things are stable, it can then release the blocked queues and let commands flow again. The prior mechanism was a lazy evaluation. That is, the next command to come down the pipe after change events would pay the full price for re-evaluation. And if this was done off of a softcall, it really could hang up the system. These changes brings the FreeBSD port more in line with the Solaris, Linux and NetBSD ports. It also, more importantly, gets us being more proactive about topology changes which could then be reflected upwards to CAM so that the periph driver can be informed sooner rather than later when things arrive or depart. --- Add in the (correct) usage of locking macros- we now have lock transition macros which allow us to transition from holding the CAM lock (Giant) and grabbing the softc lock and vice versa. Switch over to having this HBA do real locking. Some folks claim this won't be a win. They're right. But you have to start somewhere, and this will begin to teach us how to DTRT for HBAs, etc. -- Start putting in prototype 2300 support. Add back in LIP and Loop Reset as async events that each platform will handle. Add in another int_bogus instrumentation point. Do some more substantial target mode cleanups. MFC after: 8 weeks
Diffstat (limited to 'sys/dev/isp/isp_freebsd.c')
-rw-r--r--sys/dev/isp/isp_freebsd.c486
1 files changed, 376 insertions, 110 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index 2a11c54..008da7b 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -26,17 +26,43 @@
* SUCH DAMAGE.
*/
#include <dev/isp/isp_freebsd.h>
+#include <sys/unistd.h>
+#include <sys/kthread.h>
#include <machine/stdarg.h> /* for use by isp_prt below */
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <dev/isp/isp_ioctl.h>
+static d_ioctl_t ispioctl;
static void isp_intr_enable(void *);
static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
static void isp_poll(struct cam_sim *);
+#if 0
static void isp_relsim(void *);
+#endif
static timeout_t isp_watchdog;
+static void isp_kthread(void *);
static void isp_action(struct cam_sim *, union ccb *);
+#define ISP_CDEV_MAJOR 248
+static struct cdevsw isp_cdevsw = {
+ /* open */ nullopen,
+ /* close */ nullclose,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ ispioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "isp",
+ /* maj */ ISP_CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ D_TAPE,
+};
+
static struct ispsoftc *isplist = NULL;
void
@@ -91,6 +117,7 @@ isp_attach(struct ispsoftc *isp)
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path(sim));
cam_sim_free(sim, TRUE);
+ config_intrhook_disestablish(&isp->isp_osinfo.ehook);
return;
}
@@ -102,6 +129,23 @@ isp_attach(struct ispsoftc *isp)
xpt_action((union ccb *)&csa);
isp->isp_sim = sim;
isp->isp_path = path;
+ /*
+ * Create a kernel thread for fibre channel instances. We
+ * don't have dual channel FC cards.
+ */
+ if (IS_FC(isp)) {
+ cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
+ if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
+ RFHIGHPID, "%s: fc_thrd",
+ device_get_nameunit(isp->isp_dev))) {
+ isp_prt(isp, ISP_LOGERR, "could not create kthread");
+ xpt_bus_deregister(cam_sim_path(sim));
+ cam_sim_free(sim, TRUE);
+ config_intrhook_disestablish(&isp->isp_osinfo.ehook);
+ return;
+ }
+ }
+
/*
* If we have a second channel, construct SIM entry for that.
@@ -113,12 +157,14 @@ isp_attach(struct ispsoftc *isp)
xpt_bus_deregister(cam_sim_path(isp->isp_sim));
xpt_free_path(isp->isp_path);
cam_simq_free(devq);
+ config_intrhook_disestablish(&isp->isp_osinfo.ehook);
return;
}
if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
xpt_bus_deregister(cam_sim_path(isp->isp_sim));
xpt_free_path(isp->isp_path);
cam_sim_free(sim, TRUE);
+ config_intrhook_disestablish(&isp->isp_osinfo.ehook);
return;
}
@@ -128,6 +174,7 @@ isp_attach(struct ispsoftc *isp)
xpt_free_path(isp->isp_path);
xpt_bus_deregister(cam_sim_path(sim));
cam_sim_free(sim, TRUE);
+ config_intrhook_disestablish(&isp->isp_osinfo.ehook);
return;
}
@@ -140,6 +187,13 @@ isp_attach(struct ispsoftc *isp)
isp->isp_sim2 = sim;
isp->isp_path2 = path;
}
+
+ /*
+ * Create device nodes
+ */
+ (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
+ GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
+
if (isp->isp_role != ISP_ROLE_NONE) {
isp->isp_state = ISP_RUNSTATE;
ENABLE_INTS(isp);
@@ -153,6 +207,89 @@ isp_attach(struct ispsoftc *isp)
}
tmp->isp_osinfo.next = isp;
}
+
+}
+
+static int
+ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+{
+ struct ispsoftc *isp;
+ int retval = ENOTTY;
+
+ isp = isplist;
+ while (isp) {
+ if (minor(dev) == device_get_unit(isp->isp_dev)) {
+ break;
+ }
+ isp = isp->isp_osinfo.next;
+ }
+ if (isp == NULL)
+ return (ENXIO);
+
+ switch (cmd) {
+ case ISP_SDBLEV:
+ {
+ int olddblev = isp->isp_dblev;
+ isp->isp_dblev = *(int *)addr;
+ *(int *)addr = olddblev;
+ retval = 0;
+ break;
+ }
+ case ISP_RESETHBA:
+ ISP_LOCK(isp);
+ isp_reinit(isp);
+ ISP_UNLOCK(isp);
+ retval = 0;
+ break;
+ case ISP_FC_RESCAN:
+ if (IS_FC(isp)) {
+ ISP_LOCK(isp);
+ if (isp_fc_runstate(isp, 5 * 1000000)) {
+ retval = EIO;
+ } else {
+ retval = 0;
+ }
+ ISP_UNLOCK(isp);
+ }
+ break;
+ case ISP_FC_LIP:
+ if (IS_FC(isp)) {
+ ISP_LOCK(isp);
+ if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
+ retval = EIO;
+ } else {
+ retval = 0;
+ }
+ ISP_UNLOCK(isp);
+ }
+ break;
+ case ISP_FC_GETDINFO:
+ {
+ struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
+ struct lportdb *lp;
+
+ if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
+ retval = EINVAL;
+ break;
+ }
+ ISP_LOCK(isp);
+ lp = &FCPARAM(isp)->portdb[ifc->loopid];
+ if (lp->valid) {
+ ifc->loopid = lp->loopid;
+ ifc->portid = lp->portid;
+ ifc->node_wwn = lp->node_wwn;
+ ifc->port_wwn = lp->port_wwn;
+ retval = 0;
+ } else {
+ retval = ENODEV;
+ }
+ ISP_UNLOCK(isp);
+ break;
+ }
+ default:
+ break;
+ }
+ return (retval);
}
static void
@@ -198,7 +335,6 @@ static __inline int
is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
{
tstate_t *tptr;
- ISP_LOCK(isp);
tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
if (tptr == NULL) {
ISP_UNLOCK(isp);
@@ -210,7 +346,6 @@ is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
return (1);
}
} while ((tptr = tptr->next) != NULL);
- ISP_UNLOCK(isp);
return (0);
}
@@ -238,28 +373,23 @@ get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun)
{
tstate_t *tptr;
- ISP_LOCK(isp);
if (lun == CAM_LUN_WILDCARD) {
tptr = &isp->isp_osinfo.tsdflt[bus];
tptr->hold++;
- ISP_UNLOCK(isp);
return (tptr);
} else {
tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
}
if (tptr == NULL) {
- ISP_UNLOCK(isp);
return (NULL);
}
do {
if (tptr->lun == lun && tptr->bus == bus) {
tptr->hold++;
- ISP_UNLOCK(isp);
return (tptr);
}
} while ((tptr = tptr->next) != NULL);
- ISP_UNLOCK(isp);
return (tptr);
}
@@ -273,28 +403,23 @@ rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr)
static __inline int
isp_psema_sig_rqe(struct ispsoftc *isp)
{
- ISP_LOCK(isp);
while (isp->isp_osinfo.tmflags & TM_BUSY) {
isp->isp_osinfo.tmflags |= TM_WANTED;
if (tsleep(&isp->isp_osinfo.tmflags, PRIBIO|PCATCH, "i0", 0)) {
- ISP_UNLOCK(isp);
return (-1);
}
isp->isp_osinfo.tmflags |= TM_BUSY;
}
- ISP_UNLOCK(isp);
return (0);
}
static __inline int
isp_cv_wait_timed_rqe(struct ispsoftc *isp, int timo)
{
- ISP_LOCK(isp);
if (tsleep(&isp->isp_osinfo.rstatus, PRIBIO, "qt1", timo)) {
ISP_UNLOCK(isp);
return (-1);
}
- ISP_UNLOCK(isp);
return (0);
}
@@ -308,13 +433,11 @@ isp_cv_signal_rqe(struct ispsoftc *isp, int status)
static __inline void
isp_vsema_rqe(struct ispsoftc *isp)
{
- ISP_LOCK(isp);
if (isp->isp_osinfo.tmflags & TM_WANTED) {
isp->isp_osinfo.tmflags &= ~TM_WANTED;
wakeup(&isp->isp_osinfo.tmflags);
}
isp->isp_osinfo.tmflags &= ~TM_BUSY;
- ISP_UNLOCK(isp);
}
static cam_status
@@ -351,7 +474,6 @@ create_lun_state(struct ispsoftc *isp, int bus,
new->hold = 1;
hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
- ISP_LOCK(isp);
tptr = isp->isp_osinfo.lun_hash[hfx];
if (tptr == NULL) {
isp->isp_osinfo.lun_hash[hfx] = new;
@@ -360,7 +482,6 @@ create_lun_state(struct ispsoftc *isp, int bus,
tptr = tptr->next;
tptr->next = new;
}
- ISP_UNLOCK(isp);
*rslt = new;
return (CAM_REQ_CMP);
}
@@ -372,14 +493,11 @@ destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
tstate_t *lw, *pw;
hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
- ISP_LOCK(isp);
if (tptr->hold) {
- ISP_UNLOCK(isp);
return;
}
pw = isp->isp_osinfo.lun_hash[hfx];
if (pw == NULL) {
- ISP_UNLOCK(isp);
return;
} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
isp->isp_osinfo.lun_hash[hfx] = pw->next;
@@ -400,9 +518,11 @@ destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
}
}
free(tptr, M_DEVBUF);
- ISP_UNLOCK(isp);
}
+/*
+ * we enter with our locks held.
+ */
static void
isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
{
@@ -410,7 +530,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
struct ccb_en_lun *cel = &ccb->cel;
tstate_t *tptr;
u_int16_t rstat;
- int bus, frozen = 0;
+ int bus, cmd, frozen = 0;
lun_id_t lun;
target_id_t tgt;
@@ -461,9 +581,8 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
xpt_freeze_simq(isp->isp_sim, 1);
isp->isp_osinfo.drain = 1;
while (isp->isp_osinfo.drain) {
- (void) msleep(&isp->isp_osinfo.drain,
- &isp->isp_osinfo.lock, PRIBIO,
- "ispdrain", 10 * hz);
+ (void) msleep(&isp->isp_osinfo.drain, &isp->isp_lock,
+ PRIBIO, "ispdrain", 10 * hz);
}
ISP_UNLOCK(isp);
}
@@ -479,17 +598,18 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
fcparam *fcp = isp->isp_param;
int rv;
- ISP_LOCK(isp);
rv = isp_fc_runstate(isp, 2 * 1000000);
- ISP_UNLOCK(isp);
if (fcp->isp_fwstate != FW_READY ||
fcp->isp_loopstate != LOOP_READY) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGWARN,
"could not get a good port database read");
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
}
@@ -506,8 +626,11 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
if (cel->enable) {
if (isp->isp_osinfo.tmflags & (1 << bus)) {
ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
ccb->ccb_h.status =
@@ -516,56 +639,68 @@ 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) {
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
SLIST_INIT(&tptr->atios);
SLIST_INIT(&tptr->inots);
av |= ENABLE_TARGET_FLAG;
- ISP_LOCK(isp);
av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
if (av) {
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
xpt_free_path(tptr->owner);
- ISP_UNLOCK(isp);
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
isp->isp_osinfo.tmflags |= (1 << bus);
- ISP_UNLOCK(isp);
} else {
if ((isp->isp_osinfo.tmflags & (1 << bus)) == 0) {
ccb->ccb_h.status = CAM_LUN_INVALID;
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
if (are_any_luns_enabled(isp, bus)) {
ccb->ccb_h.status = CAM_SCSI_BUSY;
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
- ISP_LOCK(isp);
av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
if (av) {
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- ISP_UNLOCK(isp);
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
isp->isp_osinfo.tmflags &= ~(1 << bus);
- ISP_UNLOCK(isp);
ccb->ccb_h.status = CAM_REQ_CMP;
}
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGINFO, "Target Mode %sabled on channel %d",
(cel->enable) ? "en" : "dis", bus);
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
return;
}
@@ -573,8 +708,11 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
* We can move along now...
*/
- if (frozen)
+ if (frozen) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
if (cel->enable) {
@@ -599,11 +737,24 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
return;
}
- ISP_LOCK(isp);
if (cel->enable) {
u_int32_t seq = isp->isp_osinfo.rollinfo++;
+ int c, n, ulun = lun;
+
+ cmd = RQSTYPE_ENABLE_LUN;
+ c = DFLT_CMND_CNT;
+ n = DFLT_INOT_CNT;
+ if (IS_FC(isp) && lun != 0) {
+ cmd = RQSTYPE_MODIFY_LUN;
+ n = 0;
+ /*
+ * For SCC firmware, we only deal with setting
+ * (enabling or modifying) lun 0.
+ */
+ ulun = 0;
+ }
rstat = LUN_ERR;
- if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) {
+ 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;
@@ -611,23 +762,35 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
if (isp_cv_wait_timed_rqe(isp, 30 * hz)) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGERR,
- "wait for ENABLE LUN timed out");
+ "wait for ENABLE/MODIFY LUN timed out");
goto out;
}
rstat = isp->isp_osinfo.rstatus;
if (rstat != LUN_OK) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGERR,
- "ENABLE LUN returned 0x%x", rstat);
+ "ENABLE/MODIFY LUN returned 0x%x", rstat);
goto out;
}
} else {
+ int c, n, ulun = lun;
u_int32_t seq;
- seq = isp->isp_osinfo.rollinfo++;
rstat = LUN_ERR;
+ seq = isp->isp_osinfo.rollinfo++;
+ cmd = -RQSTYPE_MODIFY_LUN;
- if (isp_lun_cmd(isp, -RQSTYPE_MODIFY_LUN, bus, tgt, lun, seq)) {
+ c = DFLT_CMND_CNT;
+ n = DFLT_INOT_CNT;
+ if (IS_FC(isp) && lun != 0) {
+ n = 0;
+ /*
+ * For SCC firmware, we only deal with setting
+ * (enabling or modifying) lun 0.
+ */
+ 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;
@@ -645,10 +808,15 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
"MODIFY LUN returned 0x%x", rstat);
goto out;
}
- rstat = LUN_ERR;
+ if (IS_FC(isp) && lun) {
+ goto out;
+ }
+
seq = isp->isp_osinfo.rollinfo++;
- if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) {
+ 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;
@@ -656,20 +824,19 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
if (isp_cv_wait_timed_rqe(isp, 30 * hz)) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGERR,
- "wait for ENABLE LUN timed out");
+ "wait for DISABLE LUN timed out");
goto out;
}
rstat = isp->isp_osinfo.rstatus;
if (rstat != LUN_OK) {
xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGWARN,
- "ENABLE LUN returned 0x%x", rstat);
+ "DISABLE LUN returned 0x%x", rstat);
goto out;
}
}
out:
isp_vsema_rqe(isp);
- ISP_UNLOCK(isp);
if (rstat != LUN_OK) {
xpt_print_path(ccb->ccb_h.path);
@@ -867,7 +1034,7 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
cto->ct_timeout = 10;
hp = &cto->ct_syshandle;
ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
- if (cto->ct_flags & CT_SENDSTATUS)
+ if (cto->ct_flags & CT_SENDSTATUS)
cto->ct_flags |= CT_CCINCR;
}
@@ -1005,9 +1172,7 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
* If QLTM_SVALID is set, the firware has recommended Sense Data.
*
* If the DISCONNECTS DISABLED bit is set in the flags field,
- * we're still connected on the SCSI bus - i.e. the initiator
- * did not set DiscPriv in the identify message. We don't care
- * about this so it's ignored.
+ * we're still connected on the SCSI bus.
*/
status = aep->at_status;
if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
@@ -1021,15 +1186,13 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
return (0);
}
if ((status & ~QLTM_SVALID) != AT_CDB) {
- isp_prt(isp,
- ISP_LOGWARN, "bogus atio (0x%x) leaked to platform",
+ isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
status);
isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
return (0);
}
- bus = aep->at_iid >> 7;
- aep->at_iid &= 0x7f;
+ bus = GET_BUS_VAL(aep->at_iid);
tptr = get_lun_statep(isp, bus, aep->at_lun);
if (tptr == NULL) {
tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
@@ -1062,7 +1225,7 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
xpt_print_path(tptr->owner);
isp_prt(isp, ISP_LOGWARN,
"no ATIOS for lun %d from initiator %d on channel %d",
- aep->at_lun, aep->at_iid, bus);
+ aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
rls_lun_statep(isp, tptr);
if (aep->at_flags & AT_TQAE)
isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
@@ -1089,7 +1252,7 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
atiop->sense_len = 0;
}
- atiop->init_id = aep->at_iid & 0x7f;
+ atiop->init_id = GET_IID_VAL(aep->at_iid);
atiop->cdb_len = aep->at_cdblen;
MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
atiop->ccb_h.status = CAM_CDB_RECVD;
@@ -1104,10 +1267,11 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
}
xpt_done((union ccb*)atiop);
isp_prt(isp, ISP_LOGTDEBUG1,
- "ATIO[%x] CDB=0x%x iid%d->lun%d tag 0x%x ttype 0x%x %s",
- aep->at_handle, aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_lun,
- aep->at_tag_val & 0xff, aep->at_tag_type,
- (aep->at_flags & AT_NODISC)? "nondisc" : "disconnecting");
+ "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
+ aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
+ GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
+ aep->at_tag_type, (aep->at_flags & AT_NODISC)?
+ "nondisc" : "disconnecting");
rls_lun_statep(isp, tptr);
return (0);
}
@@ -1280,8 +1444,9 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
(ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
sentstatus? "FIN" : "MID");
notify_cam = ct->ct_header.rqs_seqno & 0x1;
- if (ct->ct_flags & CT2_DATAMASK)
+ if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
resid = ct->ct_resid;
+ }
} else {
ct_entry_t *ct = arg;
sentstatus = ct->ct_flags & CT_SENDSTATUS;
@@ -1302,7 +1467,7 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
* the auto-replenish feature for CTIOs.
*/
notify_cam = ct->ct_header.rqs_seqno & 0x1;
- if (ct->ct_status & QLTM_SVALID) {
+ if (ct->ct_status & QLTM_SVALID) {
char *sp = (char *)ct;
sp += CTIO_SENSE_OFFSET;
ccb->csio.sense_len =
@@ -1310,8 +1475,9 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
}
- if (ct->ct_flags & CT_DATAMASK)
+ if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
resid = ct->ct_resid;
+ }
}
ccb->csio.resid += resid;
@@ -1397,6 +1563,7 @@ isp_poll(struct cam_sim *sim)
ISP_UNLOCK(isp);
}
+#if 0
static void
isp_relsim(void *arg)
{
@@ -1412,6 +1579,7 @@ isp_relsim(void *arg)
}
ISP_UNLOCK(isp);
}
+#endif
static void
isp_watchdog(void *arg)
@@ -1497,6 +1665,61 @@ isp_watchdog(void *arg)
ISP_UNLOCK(isp);
}
+#ifdef ISP_SMPLOCK
+static void
+isp_kthread(void *arg)
+{
+ int wasfrozen;
+ struct ispsoftc *isp = arg;
+
+ mtx_lock(&isp->isp_lock);
+ for (;;) {
+ isp_prt(isp, ISP_LOGDEBUG0, "kthread checking FC state");
+ while (isp_fc_runstate(isp, 2 * 1000000) != 0) {
+#if 0
+ msleep(&lbolt, &isp->isp_lock,
+ PRIBIO, "isp_fcthrd", 0);
+#else
+ msleep(isp_kthread, &isp->isp_lock,
+ PRIBIO, "isp_fcthrd", hz);
+#endif
+ }
+ wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
+ isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
+ if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
+ isp_prt(isp, ISP_LOGDEBUG0, "kthread up release simq");
+ ISPLOCK_2_CAMLOCK(isp);
+ xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
+ cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock);
+ }
+}
+#else
+static void
+isp_kthread(void *arg)
+{
+ int wasfrozen;
+ struct ispsoftc *isp = arg;
+
+ mtx_lock(&Giant);
+ for (;;) {
+ isp_prt(isp, ISP_LOGDEBUG0, "kthread checking FC state");
+ while (isp_fc_runstate(isp, 2 * 1000000) != 0) {
+ tsleep(isp_kthread, PRIBIO, "isp_fcthrd", hz);
+ }
+ wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
+ isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
+ if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
+ isp_prt(isp, ISP_LOGDEBUG0, "kthread up release simq");
+ ISPLOCK_2_CAMLOCK(isp);
+ xpt_release_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
+ tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "isp_fc_worker", 0);
+ }
+}
+#endif
static void
isp_action(struct cam_sim *sim, union ccb *ccb)
{
@@ -1511,7 +1734,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.sim_priv.entries[1].ptr = isp;
if (isp->isp_state != ISP_RUNSTATE &&
ccb->ccb_h.func_code == XPT_SCSI_IO) {
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
isp_init(isp);
if (isp->isp_state != ISP_INITSTATE) {
ISP_UNLOCK(isp);
@@ -1524,10 +1747,11 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
return;
}
isp->isp_state = ISP_RUNSTATE;
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
}
isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
+
switch (ccb->ccb_h.func_code) {
case XPT_SCSI_IO: /* Execute the requested I/O operation */
/*
@@ -1555,9 +1779,8 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
#endif
((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
error = isp_start((XS_T *) ccb);
- ISP_UNLOCK(isp);
switch (error) {
case CMD_QUEUED:
ccb->ccb_h.status |= CAM_SIM_QUEUED;
@@ -1578,14 +1801,27 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
} else {
callout_handle_init(&ccb->ccb_h.timeout_ch);
}
+ ISPLOCK_2_CAMLOCK(isp);
break;
case CMD_RQLATER:
+#ifdef ISP_SMPLOCK
+ cv_signal(&isp->isp_osinfo.kthread_cv);
+#else
+ wakeup(&isp->isp_osinfo.kthread_cv);
+#endif
if (isp->isp_osinfo.simqfrozen == 0) {
isp_prt(isp, ISP_LOGDEBUG2,
"RQLATER freeze simq");
+#if 0
isp->isp_osinfo.simqfrozen |= SIMQFRZ_TIMED;
timeout(isp_relsim, isp, 500);
+#else
+ isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
+#endif
+ ISPLOCK_2_CAMLOCK(isp);
xpt_freeze_simq(sim, 1);
+ } else {
+ ISPLOCK_2_CAMLOCK(isp);
}
XS_SETERR(ccb, CAM_REQUEUE_REQ);
xpt_done(ccb);
@@ -1598,12 +1834,12 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
XS_SETERR(ccb, CAM_REQUEUE_REQ);
+ ISPLOCK_2_CAMLOCK(isp);
xpt_done(ccb);
break;
case CMD_COMPLETE:
- ISP_LOCK(isp);
isp_done((struct ccb_scsiio *) ccb);
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
break;
default:
isp_prt(isp, ISP_LOGERR,
@@ -1611,12 +1847,15 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
error, __LINE__, __FILE__);
XS_SETERR(ccb, CAM_REQ_CMP_ERR);
xpt_done(ccb);
+ ISPLOCK_2_CAMLOCK(isp);
}
break;
#ifdef ISP_TARGET_MODE
case XPT_EN_LUN: /* Enable LUN as a target */
+ CAMLOCK_2_ISPLOCK(isp);
isp_en_lun(isp, ccb);
+ ISPLOCK_2_CAMLOCK(isp);
xpt_done(ccb);
break;
@@ -1633,7 +1872,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
ccb->ccb_h.sim_priv.entries[0].field = 0;
ccb->ccb_h.sim_priv.entries[1].ptr = isp;
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
SLIST_INSERT_HEAD(&tptr->atios,
&ccb->ccb_h, sim_links.sle);
@@ -1641,14 +1880,14 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
sim_links.sle);
}
- ISP_UNLOCK(isp);
rls_lun_statep(isp, tptr);
ccb->ccb_h.status = CAM_REQ_INPROG;
+ ISPLOCK_2_CAMLOCK(isp);
break;
}
case XPT_CONT_TARGET_IO:
{
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
ccb->ccb_h.status = isp_target_start_ctio(isp, ccb);
if (ccb->ccb_h.status != CAM_REQ_INPROG) {
if (isp->isp_osinfo.simqfrozen == 0) {
@@ -1659,11 +1898,12 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
XS_SETERR(ccb, CAM_REQUEUE_REQ);
+ ISPLOCK_2_CAMLOCK(isp);
xpt_done(ccb);
} else {
+ ISPLOCK_2_CAMLOCK(isp);
ccb->ccb_h.status |= CAM_SIM_QUEUED;
}
- ISP_UNLOCK(isp);
break;
}
#endif
@@ -1673,9 +1913,9 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
tgt = ccb->ccb_h.target_id;
tgt |= (bus << 16);
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
if (error) {
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
} else {
@@ -1686,6 +1926,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
case XPT_ABORT: /* Abort the specified CCB */
{
union ccb *accb = ccb->cab.abort_ccb;
+ CAMLOCK_2_ISPLOCK(isp);
switch (accb->ccb_h.func_code) {
#ifdef ISP_TARGET_MODE
case XPT_ACCEPT_TARGET_IO:
@@ -1698,9 +1939,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
break;
#endif
case XPT_SCSI_IO:
- ISP_LOCK(isp);
error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
- ISP_UNLOCK(isp);
if (error) {
ccb->ccb_h.status = CAM_UA_ABORT;
} else {
@@ -1711,6 +1950,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.status = CAM_REQ_INVALID;
break;
}
+ ISPLOCK_2_CAMLOCK(isp);
xpt_done(ccb);
break;
}
@@ -1718,7 +1958,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
cts = &ccb->cts;
tgt = cts->ccb_h.target_id;
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
if (IS_SCSI(isp)) {
sdparam *sdp = isp->isp_param;
u_int16_t *dptr;
@@ -1795,7 +2035,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
sdp->isp_devparam[tgt].dev_update = 1;
isp->isp_update |= (1 << bus);
}
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
break;
@@ -1823,14 +2063,13 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
u_int16_t dval, pval, oval;
int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
+ CAMLOCK_2_ISPLOCK(isp);
sdp += bus;
if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) {
- ISP_LOCK(isp);
sdp->isp_devparam[tgt].dev_refresh = 1;
isp->isp_update |= (1 << bus);
(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
NULL);
- ISP_UNLOCK(isp);
dval = sdp->isp_devparam[tgt].cur_dflags;
oval = sdp->isp_devparam[tgt].cur_offset;
pval = sdp->isp_devparam[tgt].cur_period;
@@ -1840,7 +2079,6 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
pval = sdp->isp_devparam[tgt].sync_period;
}
- ISP_LOCK(isp);
cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
if (dval & DPARM_DISC) {
@@ -1864,7 +2102,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
CCB_TRANS_SYNC_RATE_VALID |
CCB_TRANS_SYNC_OFFSET_VALID;
}
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
isp_prt(isp, ISP_LOGDEBUG0,
"%d.%d get %s period 0x%x offset 0x%x flags 0x%x",
bus, tgt, (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
@@ -1905,9 +2143,9 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
case XPT_RESET_BUS: /* Reset the specified bus */
bus = cam_sim_bus(sim);
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
- ISP_UNLOCK(isp);
+ ISPLOCK_2_CAMLOCK(isp);
if (error)
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
else {
@@ -2050,15 +2288,9 @@ isp_done(struct ccb_scsiio *sccb)
"finished command on borrowed time");
}
XS_CMD_S_CLEAR(sccb);
- ISP_UNLOCK(isp);
-#ifdef ISP_SMPLOCK
- mtx_lock(&Giant);
- xpt_done((union ccb *) sccb);
- mtx_unlock(&Giant);
-#else
+ ISPLOCK_2_CAMLOCK(isp);
xpt_done((union ccb *) sccb);
-#endif
- ISP_LOCK(isp);
+ CAMLOCK_2_ISPLOCK(isp);
}
}
@@ -2109,7 +2341,9 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
"NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
bus, tgt, neg.sync_period, neg.sync_offset, flags);
xpt_setup_ccb(&neg.ccb_h, tmppath, 1);
+ ISPLOCK_2_CAMLOCK(isp);
xpt_async(AC_TRANSFER_NEG, tmppath, &neg);
+ CAMLOCK_2_ISPLOCK(isp);
xpt_free_path(tmppath);
break;
}
@@ -2118,33 +2352,60 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
bus);
if (bus > 0 && isp->isp_path2) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
+ CAMLOCK_2_ISPLOCK(isp);
} else if (isp->isp_path) {
+ ISPLOCK_2_CAMLOCK(isp);
xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
+ CAMLOCK_2_ISPLOCK(isp);
}
break;
+ case ISPASYNC_LIP:
+ if (isp->isp_path) {
+ if (isp->isp_osinfo.simqfrozen == 0) {
+ isp_prt(isp, ISP_LOGDEBUG0, "LIP freeze simq");
+ ISPLOCK_2_CAMLOCK(isp);
+ xpt_freeze_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
+ isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
+ }
+ isp_prt(isp, ISP_LOGINFO, "LIP Received");
+ break;
+ case ISPASYNC_LOOP_RESET:
+ if (isp->isp_path) {
+ if (isp->isp_osinfo.simqfrozen == 0) {
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "Loop Reset freeze simq");
+ ISPLOCK_2_CAMLOCK(isp);
+ xpt_freeze_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
+ }
+ isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
+ }
+ isp_prt(isp, ISP_LOGINFO, "Loop Reset Received");
+ break;
case ISPASYNC_LOOP_DOWN:
if (isp->isp_path) {
if (isp->isp_osinfo.simqfrozen == 0) {
- isp_prt(isp, ISP_LOGDEBUG2,
+ isp_prt(isp, ISP_LOGDEBUG0,
"loop down freeze simq");
+ ISPLOCK_2_CAMLOCK(isp);
xpt_freeze_simq(isp->isp_sim, 1);
+ CAMLOCK_2_ISPLOCK(isp);
}
isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
}
isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
break;
case ISPASYNC_LOOP_UP:
- if (isp->isp_path) {
- int wasfrozen =
- isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
- isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
- if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
- xpt_release_simq(isp->isp_sim, 1);
- isp_prt(isp, ISP_LOGDEBUG2,
- "loop up release simq");
- }
- }
+ /*
+ * Now we just note that Loop has come up. We don't
+ * actually do anything because we're waiting for a
+ * Change Notify before activating the FC cleanup
+ * thread to look at the state of the loop again.
+ */
isp_prt(isp, ISP_LOGINFO, "Loop UP");
break;
case ISPASYNC_PROMENADE:
@@ -2175,6 +2436,11 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
isp_prt(isp, ISP_LOGINFO,
"Name Server Database Changed");
}
+#ifdef ISP_SMPLOCK
+ cv_signal(&isp->isp_osinfo.kthread_cv);
+#else
+ wakeup(&isp->isp_osinfo.kthread_cv);
+#endif
break;
case ISPASYNC_FABRIC_DEV:
{
OpenPOWER on IntegriCloud