PERFORCE change 197237 for review
Matt Jacob
mjacob at FreeBSD.org
Fri Aug 5 22:32:50 UTC 2011
http://p4web.freebsd.org/@@197237?ac=10
Change 197237 by mjacob at mjacob-sandbox on 2011/08/05 22:32:09
Merge changes from Panasas for isp. Mostly in implementing taskqueues
for loop down and gone device events.
Affected files ...
.. //depot/projects/mjacob-dev/sys/dev/isp/isp.c#5 edit
.. //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.c#6 edit
.. //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.h#6 edit
.. //depot/projects/mjacob-dev/sys/dev/isp/ispvar.h#5 edit
Differences ...
==== //depot/projects/mjacob-dev/sys/dev/isp/isp.c#5 (text+ko) ====
@@ -102,7 +102,6 @@
/*
* Local function prototypes.
*/
-static void isp_prt_endcmd(ispsoftc_t *, XS_T *);
static int isp_parse_async(ispsoftc_t *, uint16_t);
static int isp_parse_async_fc(ispsoftc_t *, uint16_t);
static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *);
@@ -5391,7 +5390,7 @@
* Support routines.
*/
-static void
+void
isp_prt_endcmd(ispsoftc_t *isp, XS_T *xs)
{
char cdbstr[16 * 5 + 1];
==== //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.c#6 (text+ko) ====
@@ -67,7 +67,10 @@
static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
static void isp_poll(struct cam_sim *);
static timeout_t isp_watchdog;
+static timeout_t isp_gdt;
+static task_fn_t isp_gdt_task;
static timeout_t isp_ldt;
+static task_fn_t isp_ldt_task;
static void isp_kthread(void *);
static void isp_action(struct cam_sim *, union ccb *);
#ifdef ISP_INTERNAL_TARGET
@@ -141,8 +144,11 @@
fc->path = path;
fc->isp = isp;
fc->ready = 1;
+
callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
+ TASK_INIT(&fc->ltask, 1, isp_ldt_task, fc);
+ TASK_INIT(&fc->gtask, 1, isp_gdt_task, fc);
/*
* We start by being "loop down" if we have an initiator role
@@ -303,6 +309,20 @@
}
}
+static void
+isp_unfreeze_loopdown(ispsoftc_t *isp, int chan)
+{
+ if (IS_FC(isp)) {
+ struct isp_fc *fc = ISP_FC_PC(isp, chan);
+ int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
+ fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
+ if (wasfrozen && fc->simqfrozen == 0) {
+ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
+ xpt_release_simq(fc->sim, 1);
+ }
+ }
+}
+
static int
ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
@@ -3837,12 +3857,33 @@
{
struct ccb_scsiio *xs = arg;
ispsoftc_t *isp;
- uint32_t handle;
+ uint32_t ohandle = ISP_HANDLE_FREE, handle;
isp = XS_ISP(xs);
handle = isp_find_handle(isp, xs);
+
+ if (handle != ISP_HANDLE_FREE && !XS_CMD_WPEND_P(xs)) {
+ isp_xs_prt(isp, xs, ISP_LOGWARN, "first watchdog (handle 0x%x) timed out- deferring for grace period", handle);
+ callout_reset(&PISP_PCMD(xs)->wdog, 2 * hz, isp_watchdog, xs);
+ XS_CMD_S_WPEND(xs);
+ return;
+ }
+ XS_C_TACTIVE(xs);
+
+ /*
+ * Hand crank the interrupt code just to be sure the command isn't stuck somewhere.
+ */
if (handle != ISP_HANDLE_FREE) {
+ uint32_t isr;
+ uint16_t sema, mbox;
+ if (ISP_READ_ISR(isp, &isr, &sema, &mbox) != 0) {
+ isp_intr(isp, isr, sema, mbox);
+ }
+ ohandle = handle;
+ handle = isp_find_handle(isp, xs);
+ }
+ if (handle != ISP_HANDLE_FREE) {
/*
* Try and make sure the command is really dead before
* we release the handle (and DMA resources) for reuse.
@@ -3878,7 +3919,14 @@
isp_destroy_handle(isp, handle);
isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle);
XS_SETERR(xs, CAM_CMD_TIMEOUT);
+ isp_prt_endcmd(isp, xs);
isp_done(xs);
+ } else {
+ if (ohandle != ISP_HANDLE_FREE) {
+ isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle 0x%x, recovered during interrupt", __func__, ohandle);
+ } else {
+ isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle already free", __func__);
+ }
}
}
@@ -3937,12 +3985,20 @@
isp_gdt(void *arg)
{
struct isp_fc *fc = arg;
+ taskqueue_enqueue_fast(taskqueue_fast, &fc->gtask);
+}
+
+static void
+isp_gdt_task(void *arg, int pending)
+{
+ struct isp_fc *fc = arg;
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
fcportdb_t *lp;
int dbidx, tgt, more_to_do = 0;
- isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d GDT timer expired @ %lu", chan, (unsigned long) time_uptime);
+ ISP_LOCK(isp);
+ isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan);
for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
lp = &FCPARAM(isp, chan)->portdb[dbidx];
@@ -3971,6 +4027,7 @@
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Stopping Gone Device Timer", chan);
}
}
+ ISP_UNLOCK(isp);
}
/*
@@ -3986,11 +4043,19 @@
isp_ldt(void *arg)
{
struct isp_fc *fc = arg;
+ taskqueue_enqueue_fast(taskqueue_fast, &fc->ltask);
+}
+
+static void
+isp_ldt_task(void *arg, int pending)
+{
+ struct isp_fc *fc = arg;
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
fcportdb_t *lp;
- int dbidx, tgt;
+ int dbidx, tgt, i;
+ ISP_LOCK(isp);
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime);
/*
@@ -4009,7 +4074,24 @@
/*
* XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
*/
+
+
+ for (i = 0; i < isp->isp_maxcmds; i++) {
+ struct ccb_scsiio *xs;
+ if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) {
+ continue;
+ }
+ if ((xs = isp->isp_xflist[i].cmd) == NULL) {
+ continue;
+ }
+ if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) {
+ continue;
+ }
+ isp_prt(isp, ISP_LOGWARN, "command handle 0x%08x for %d.%d.%d orphaned by loop down timeout",
+ isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs));
+ }
+
/*
* Mark that we've announced that this device is gone....
*/
@@ -4030,6 +4112,10 @@
isp_make_gone(isp, chan, tgt);
}
+ if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) {
+ isp_unfreeze_loopdown(isp, chan);
+ }
+
/*
* The loop down timer has expired. Wake up the kthread
* to notice that fact (or make it false).
@@ -4037,6 +4123,7 @@
fc->loop_dead = 1;
fc->loop_down_time = fc->loop_down_limit+1;
wakeup(fc);
+ ISP_UNLOCK(isp);
}
static void
@@ -4050,7 +4137,7 @@
mtx_lock(&isp->isp_osinfo.lock);
for (;;) {
- int wasfrozen, lb, lim;
+ int lb, lim;
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan);
lb = isp_fc_runstate(isp, chan, 250000);
@@ -4121,12 +4208,7 @@
*/
if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) {
- wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
- fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
- if (wasfrozen && fc->simqfrozen == 0) {
- isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
- xpt_release_simq(fc->sim, 1);
- }
+ isp_unfreeze_loopdown(isp, chan);
}
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp);
@@ -4225,6 +4307,7 @@
ts = 60*1000;
}
ts = isp_mstohz(ts);
+ XS_S_TACTIVE(ccb);
callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb);
break;
case CMD_RQLATER:
@@ -4751,7 +4834,9 @@
/*
* Set base transfer capabilities for Fibre Channel, for this HBA.
*/
- if (IS_24XX(isp)) {
+ if (IS_25XX(isp)) {
+ cpi->base_transfer_speed = 8000000;
+ } else if (IS_24XX(isp)) {
cpi->base_transfer_speed = 4000000;
} else if (IS_23XX(isp)) {
cpi->base_transfer_speed = 2000000;
@@ -4797,6 +4882,7 @@
isp_done(XS_T *sccb)
{
ispsoftc_t *isp = XS_ISP(sccb);
+ uint32_t status;
if (XS_NOERR(sccb))
XS_SETERR(sccb, CAM_REQ_CMP);
@@ -4811,8 +4897,10 @@
}
sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
- if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status);
+ status = sccb->ccb_h.status & CAM_STATUS_MASK;
+ if (status != CAM_REQ_CMP) {
+ if (status != CAM_SEL_TIMEOUT)
+ isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status);
if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
sccb->ccb_h.status |= CAM_DEV_QFRZN;
xpt_freeze_devq(sccb->ccb_h.path, 1);
@@ -4824,7 +4912,8 @@
}
XS_CMD_S_DONE(sccb);
- callout_stop(&PISP_PCMD(sccb)->wdog);
+ if (XS_TACTIVE_P(sccb))
+ callout_stop(&PISP_PCMD(sccb)->wdog);
XS_CMD_S_CLEAR(sccb);
isp_free_pcmd(isp, (union ccb *) sccb);
xpt_done((union ccb *) sccb);
@@ -4974,7 +5063,6 @@
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->reserved = 0;
- lp->gone_timer = 0;
if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
int dbidx = lp - FCPARAM(isp, bus)->portdb;
int i;
@@ -5010,7 +5098,6 @@
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->reserved = 0;
- lp->gone_timer = 0;
if (isp_change_is_bad) {
lp->state = FC_PORTDB_STATE_NIL;
if (lp->dev_map_idx) {
==== //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.h#6 (text+ko) ====
@@ -41,6 +41,7 @@
#include <sys/proc.h>
#include <sys/bus.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/cpu.h>
@@ -182,6 +183,8 @@
ready : 1;
struct callout ldt; /* loop down timer */
struct callout gdt; /* gone device timer */
+ struct task ltask;
+ struct task gtask;
#ifdef ISP_TARGET_MODE
struct tslist lun_hash[LUN_HASH_SIZE];
#ifdef ISP_INTERNAL_TARGET
@@ -597,12 +600,23 @@
* Platform private flags
*/
#define ISP_SPRIV_ERRSET 0x1
+#define ISP_SPRIV_TACTIVE 0x2
#define ISP_SPRIV_DONE 0x8
+#define ISP_SPRIV_WPEND 0x10
+
+#define XS_S_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_TACTIVE
+#define XS_C_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_TACTIVE
+#define XS_TACTIVE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_TACTIVE)
#define XS_CMD_S_DONE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_DONE
#define XS_CMD_C_DONE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_DONE
#define XS_CMD_DONE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_DONE)
+#define XS_CMD_S_WPEND(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_WPEND
+#define XS_CMD_C_WPEND(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_WPEND
+#define XS_CMD_WPEND_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_WPEND)
+
+
#define XS_CMD_S_CLEAR(sccb) (sccb)->ccb_h.spriv_field0 = 0
/*
==== //depot/projects/mjacob-dev/sys/dev/isp/ispvar.h#5 (text+ko) ====
@@ -953,6 +953,11 @@
#define ISPASYNC_CHANGE_OTHER 2
/*
+ * Platform Independent Error Prinout
+ */
+void isp_prt_endcmd(ispsoftc_t *, XS_T *);
+
+/*
* Platform Dependent Error and Debug Printout
*
* Two required functions for each platform must be provided:
More information about the p4-projects
mailing list