Create a kernel thread for Fibre Channel cards. This is the new
way of doing business- modulo some startup spasms and peculiarities of the way kthreads are started (*after* configuration, weird) and some strangeness with the freeze/thaw code, what now happens is that any of Loop Down, LIP, Loop Reset or Port Datbase or Name Server Database Changed ASYNC events cause the queues to freeze for this channel. The arrival of a Loop UP is not relevant. What *is* relevant is that the Port Datbase or Name Server Changed async event indicate that it's okay to go and (re)evaluate the state of the FC link and (re)probe local loop and fabric membership. We have a kthread do this because it's *sooooo* much nicer to be able to sleep while doing the 130-250 mailbox commands it'll take to re-evaluate things. When the state is well known again, we can unfreeze the channel queues. Then, as commands start arriving, we simply can start them or bounce them with XS_SELTIMEOUT (if the device in question has gone away). Previously, we did lazy evaluation, which meant that if a change occurred, we would wait until the very *next* command to go rebuild stuff. The reason this is not sensible is: a) Even with sleeping, you can hang up your system because you might be making some poor stat(2) call pay the price of re-evaluating the whole fabric. b) If we ever really want to get to dynamic attachment/detachment, we should find out sooner, rather than later, where things get to. Split off ispminphys_1020 from ispminphys- a 1020 has a 24 bit limit- not anything newer. Re-enable LIPs and Loop Resets as async events- this allows the outer layer to set policy about them. Roll platform major && minor. Remove bogus waitq (no longer used). Remove callout entry in softc (no longer used). Define some shorthands for channels. Clean up a variety of cruft left over from the thorpej_scsipi changeover.
This commit is contained in:
parent
5b51f5ebe2
commit
c9de53f96e
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: isp.c,v 1.76 2001/05/16 03:58:47 mjacob Exp $ */
|
||||
/* $NetBSD: isp.c,v 1.77 2001/05/25 21:45:55 mjacob Exp $ */
|
||||
/*
|
||||
* This driver, which is contained in NetBSD in the files:
|
||||
*
|
||||
|
@ -3367,7 +3367,7 @@ isp_parse_async(struct ispsoftc *isp, int mbox)
|
|||
FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD;
|
||||
isp->isp_sendmarker = 1;
|
||||
isp_mark_getpdb_all(isp);
|
||||
isp_prt(isp, ISP_LOGINFO, "LIP occurred");
|
||||
isp_async(isp, ISPASYNC_LIP, NULL);
|
||||
#ifdef ISP_TARGET_MODE
|
||||
isp_target_async(isp, bus, mbox);
|
||||
#endif
|
||||
|
@ -3400,7 +3400,7 @@ isp_parse_async(struct ispsoftc *isp, int mbox)
|
|||
FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
|
||||
FCPARAM(isp)->isp_loopstate = LOOP_NIL;
|
||||
isp_mark_getpdb_all(isp);
|
||||
isp_prt(isp, ISP_LOGINFO, "Loop RESET");
|
||||
isp_async(isp, ISPASYNC_LOOP_RESET, NULL);
|
||||
#ifdef ISP_TARGET_MODE
|
||||
isp_target_async(isp, bus, mbox);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: isp_netbsd.c,v 1.43 2001/05/16 03:52:10 mjacob Exp $ */
|
||||
/* $NetBSD: isp_netbsd.c,v 1.44 2001/05/25 21:45:55 mjacob Exp $ */
|
||||
/*
|
||||
* This driver, which is contained in NetBSD in the files:
|
||||
*
|
||||
|
@ -80,13 +80,17 @@
|
|||
*/
|
||||
#define _XT(xs) ((((xs)->timeout/1000) * hz) + (3 * hz))
|
||||
|
||||
static void ispminphys_1020(struct buf *);
|
||||
static void ispminphys(struct buf *);
|
||||
static void isprequest (struct scsipi_channel *, scsipi_adapter_req_t, void *);
|
||||
static INLINE void ispcmd(struct ispsoftc *, XS_T *);
|
||||
static void isprequest(struct scsipi_channel *, scsipi_adapter_req_t, void *);
|
||||
static int
|
||||
ispioctl(struct scsipi_channel *, u_long, caddr_t, int, struct proc *);
|
||||
|
||||
static void isp_polled_cmd(struct ispsoftc *, XS_T *);
|
||||
static void isp_dog(void *);
|
||||
static void isp_create_fc_worker(void *);
|
||||
static void isp_fc_worker(void *);
|
||||
|
||||
/*
|
||||
* Complete attachment of hardware, include subdevices.
|
||||
|
@ -106,7 +110,11 @@ isp_attach(struct ispsoftc *isp)
|
|||
isp->isp_osinfo._adapter.adapt_max_periph = min(isp->isp_maxcmds, 255);
|
||||
isp->isp_osinfo._adapter.adapt_ioctl = ispioctl;
|
||||
isp->isp_osinfo._adapter.adapt_request = isprequest;
|
||||
isp->isp_osinfo._adapter.adapt_minphys = ispminphys;
|
||||
if (isp->isp_type <= ISP_HA_SCSI_1020A) {
|
||||
isp->isp_osinfo._adapter.adapt_minphys = ispminphys_1020;
|
||||
} else {
|
||||
isp->isp_osinfo._adapter.adapt_minphys = ispminphys;
|
||||
}
|
||||
|
||||
isp->isp_osinfo._chan.chan_adapter = &isp->isp_osinfo._adapter;
|
||||
isp->isp_osinfo._chan.chan_bustype = &scsi_bustype;
|
||||
|
@ -117,13 +125,19 @@ isp_attach(struct ispsoftc *isp)
|
|||
*/
|
||||
isp->isp_osinfo._chan.chan_nluns = min(isp->isp_maxluns, 8);
|
||||
|
||||
TAILQ_INIT(&isp->isp_osinfo.waitq); /* The 2nd bus will share.. */
|
||||
|
||||
if (IS_FC(isp)) {
|
||||
isp->isp_osinfo._chan.chan_ntargets = MAX_FC_TARG;
|
||||
isp->isp_osinfo._chan.chan_id = MAX_FC_TARG;
|
||||
isp->isp_osinfo.threadwork = 1;
|
||||
/*
|
||||
* Note that isp_create_fc_worker won't get called
|
||||
* until much much later (after proc0 is created).
|
||||
*/
|
||||
kthread_create(isp_create_fc_worker, isp);
|
||||
} else {
|
||||
int bus = 0;
|
||||
sdparam *sdp = isp->isp_param;
|
||||
|
||||
isp->isp_osinfo._chan.chan_ntargets = MAX_TARGETS;
|
||||
isp->isp_osinfo._chan.chan_id = sdp->isp_initiator_id;
|
||||
isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id;
|
||||
|
@ -135,13 +149,6 @@ isp_attach(struct ispsoftc *isp)
|
|||
isp->isp_osinfo._chan_b.chan_id = sdp->isp_initiator_id;
|
||||
isp->isp_osinfo._chan_b.chan_channel = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a SCSI Bus Reset.
|
||||
*/
|
||||
if (IS_SCSI(isp)) {
|
||||
int bus = 0;
|
||||
ISP_LOCK(isp);
|
||||
(void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
|
||||
if (IS_DUALBUS(isp)) {
|
||||
|
@ -149,10 +156,6 @@ isp_attach(struct ispsoftc *isp)
|
|||
(void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
|
||||
}
|
||||
ISP_UNLOCK(isp);
|
||||
} else {
|
||||
ISP_LOCK(isp);
|
||||
isp_fc_runstate(isp, 2 * 1000000);
|
||||
ISP_UNLOCK(isp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -165,28 +168,30 @@ isp_attach(struct ispsoftc *isp)
|
|||
/*
|
||||
* And attach children (if any).
|
||||
*/
|
||||
config_found((void *)isp, &isp->isp_osinfo._chan, scsiprint);
|
||||
config_found((void *)isp, &isp->isp_chanA, scsiprint);
|
||||
if (IS_DUALBUS(isp)) {
|
||||
config_found((void *)isp, &isp->isp_osinfo._chan_b, scsiprint);
|
||||
config_found((void *)isp, &isp->isp_chanB, scsiprint);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* minphys our xfers
|
||||
*
|
||||
* Unfortunately, the buffer pointer describes the target device- not the
|
||||
* adapter device, so we can't use the pointer to find out what kind of
|
||||
* adapter we are and adjust accordingly.
|
||||
*/
|
||||
|
||||
static void
|
||||
ispminphys_1020(struct buf *bp)
|
||||
{
|
||||
if (bp->b_bcount >= (1 << 24)) {
|
||||
bp->b_bcount = (1 << 24);
|
||||
}
|
||||
minphys(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
ispminphys(struct buf *bp)
|
||||
{
|
||||
/*
|
||||
* XX: Only the 1020 has a 24 bit limit.
|
||||
*/
|
||||
if (bp->b_bcount >= (1 << 24)) {
|
||||
bp->b_bcount = (1 << 24);
|
||||
if (bp->b_bcount >= (1 << 30)) {
|
||||
bp->b_bcount = (1 << 30);
|
||||
}
|
||||
minphys(bp);
|
||||
}
|
||||
|
@ -196,16 +201,16 @@ ispioctl(struct scsipi_channel *chan, u_long cmd, caddr_t addr, int flag,
|
|||
struct proc *p)
|
||||
{
|
||||
struct ispsoftc *isp = (void *)chan->chan_adapter->adapt_dev;
|
||||
int s, retval = ENOTTY;
|
||||
int retval = ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case SCBUSIORESET:
|
||||
s = splbio();
|
||||
ISP_LOCK(isp);
|
||||
if (isp_control(isp, ISPCTL_RESET_BUS, &chan->chan_channel))
|
||||
retval = EIO;
|
||||
else
|
||||
retval = 0;
|
||||
(void) splx(s);
|
||||
ISP_UNLOCK(isp);
|
||||
break;
|
||||
case ISP_SDBLEV:
|
||||
{
|
||||
|
@ -272,69 +277,153 @@ ispioctl(struct scsipi_channel *chan, u_long cmd, caddr_t addr, int flag,
|
|||
return (retval);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
ispcmd(struct ispsoftc *isp, XS_T *xs)
|
||||
{
|
||||
ISP_LOCK(isp);
|
||||
if (isp->isp_state < ISP_RUNSTATE) {
|
||||
DISABLE_INTS(isp);
|
||||
isp_init(isp);
|
||||
if (isp->isp_state != ISP_INITSTATE) {
|
||||
ENABLE_INTS(isp);
|
||||
ISP_UNLOCK(isp);
|
||||
XS_SETERR(xs, HBA_BOTCH);
|
||||
scsipi_done(xs);
|
||||
return;
|
||||
}
|
||||
isp->isp_state = ISP_RUNSTATE;
|
||||
ENABLE_INTS(isp);
|
||||
}
|
||||
/*
|
||||
* Handle the case of a FC card where the FC thread hasn't
|
||||
* fired up yet and we have loop state to clean up. If we
|
||||
* can't clear things up and we've never seen loop up, bounce
|
||||
* the command.
|
||||
*/
|
||||
if (IS_FC(isp) && isp->isp_osinfo.threadwork &&
|
||||
isp->isp_osinfo.thread == 0) {
|
||||
volatile u_int8_t ombi = isp->isp_osinfo.no_mbox_ints;
|
||||
int delay_time;
|
||||
|
||||
if (xs->xs_control & XS_CTL_POLL) {
|
||||
isp->isp_osinfo.no_mbox_ints = 1;
|
||||
}
|
||||
|
||||
if (isp->isp_osinfo.loop_checked == 0) {
|
||||
delay_time = 10 * 1000000;
|
||||
isp->isp_osinfo.loop_checked = 1;
|
||||
} else {
|
||||
delay_time = 250000;
|
||||
}
|
||||
|
||||
if (isp_fc_runstate(isp, delay_time) != 0) {
|
||||
if (xs->xs_control & XS_CTL_POLL) {
|
||||
isp->isp_osinfo.no_mbox_ints = ombi;
|
||||
}
|
||||
if (FCPARAM(isp)->loop_seen_once == 0) {
|
||||
XS_SETERR(xs, HBA_SELTIMEOUT);
|
||||
scsipi_done(xs);
|
||||
ISP_UNLOCK(isp);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Otherwise, fall thru to be queued up for later.
|
||||
*/
|
||||
} else {
|
||||
int wasblocked =
|
||||
(isp->isp_osinfo.blocked || isp->isp_osinfo.paused);
|
||||
isp->isp_osinfo.threadwork = 0;
|
||||
isp->isp_osinfo.blocked =
|
||||
isp->isp_osinfo.paused = 0;
|
||||
isp_prt(isp, ISP_LOGALL, "ispcmd, manual runstate, (freeze count %d)", isp->isp_chanA.chan_qfreeze);
|
||||
if (wasblocked) {
|
||||
scsipi_channel_thaw(&isp->isp_chanA, 1);
|
||||
}
|
||||
}
|
||||
if (xs->xs_control & XS_CTL_POLL) {
|
||||
isp->isp_osinfo.no_mbox_ints = ombi;
|
||||
}
|
||||
}
|
||||
|
||||
if (isp->isp_osinfo.paused) {
|
||||
isp_prt(isp, ISP_LOGWARN, "I/O while paused");
|
||||
xs->error = XS_RESOURCE_SHORTAGE;
|
||||
scsipi_done(xs);
|
||||
ISP_UNLOCK(isp);
|
||||
return;
|
||||
}
|
||||
if (isp->isp_osinfo.blocked) {
|
||||
isp_prt(isp, ISP_LOGWARN, "I/O while blocked");
|
||||
xs->error = XS_REQUEUE;
|
||||
scsipi_done(xs);
|
||||
ISP_UNLOCK(isp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xs->xs_control & XS_CTL_POLL) {
|
||||
volatile u_int8_t ombi = isp->isp_osinfo.no_mbox_ints;
|
||||
isp->isp_osinfo.no_mbox_ints = 1;
|
||||
isp_polled_cmd(isp, xs);
|
||||
isp->isp_osinfo.no_mbox_ints = ombi;
|
||||
ISP_UNLOCK(isp);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (isp_start(xs)) {
|
||||
case CMD_QUEUED:
|
||||
if (xs->timeout) {
|
||||
callout_reset(&xs->xs_callout, _XT(xs), isp_dog, xs);
|
||||
}
|
||||
break;
|
||||
case CMD_EAGAIN:
|
||||
isp->isp_osinfo.paused = 1;
|
||||
xs->error = XS_RESOURCE_SHORTAGE;
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
if (IS_DUALBUS(isp)) {
|
||||
scsipi_channel_freeze(&isp->isp_chanB, 1);
|
||||
}
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
case CMD_RQLATER:
|
||||
/*
|
||||
* We can only get RQLATER from FC devices (1 channel only)
|
||||
*
|
||||
* Also, if we've never seen loop up, bounce the command
|
||||
* (somebody has booted with no FC cable connected)
|
||||
*/
|
||||
if (FCPARAM(isp)->loop_seen_once == 0) {
|
||||
XS_SETERR(xs, HBA_SELTIMEOUT);
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
}
|
||||
if (isp->isp_osinfo.blocked == 0) {
|
||||
isp->isp_osinfo.blocked = 1;
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
isp_prt(isp, ISP_LOGALL, "ispcmd, RQLATER, (freeze count %d)", isp->isp_chanA.chan_qfreeze);
|
||||
}
|
||||
xs->error = XS_REQUEUE;
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
case CMD_COMPLETE:
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
}
|
||||
ISP_UNLOCK(isp);
|
||||
}
|
||||
|
||||
static void
|
||||
isprequest(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
|
||||
{
|
||||
struct scsipi_periph *periph;
|
||||
struct ispsoftc *isp = (void *)chan->chan_adapter->adapt_dev;
|
||||
XS_T *xs;
|
||||
int s, result;
|
||||
|
||||
switch (req) {
|
||||
case ADAPTER_REQ_RUN_XFER:
|
||||
xs = arg;
|
||||
periph = xs->xs_periph;
|
||||
s = splbio();
|
||||
if (isp->isp_state < ISP_RUNSTATE) {
|
||||
DISABLE_INTS(isp);
|
||||
isp_init(isp);
|
||||
if (isp->isp_state != ISP_INITSTATE) {
|
||||
ENABLE_INTS(isp);
|
||||
(void) splx(s);
|
||||
XS_SETERR(xs, HBA_BOTCH);
|
||||
scsipi_done(xs);
|
||||
return;
|
||||
}
|
||||
isp->isp_state = ISP_RUNSTATE;
|
||||
ENABLE_INTS(isp);
|
||||
}
|
||||
|
||||
if (xs->xs_control & XS_CTL_POLL) {
|
||||
volatile u_int8_t ombi = isp->isp_osinfo.no_mbox_ints;
|
||||
isp->isp_osinfo.no_mbox_ints = 1;
|
||||
isp_polled_cmd(isp, xs);
|
||||
isp->isp_osinfo.no_mbox_ints = ombi;
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
result = isp_start(xs);
|
||||
switch (result) {
|
||||
case CMD_QUEUED:
|
||||
if (xs->timeout) {
|
||||
callout_reset(&xs->xs_callout, _XT(xs),
|
||||
isp_dog, xs);
|
||||
}
|
||||
break;
|
||||
case CMD_EAGAIN:
|
||||
xs->error = XS_REQUEUE;
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
case CMD_RQLATER:
|
||||
xs->error = XS_RESOURCE_SHORTAGE;
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
case CMD_COMPLETE:
|
||||
scsipi_done(xs);
|
||||
break;
|
||||
}
|
||||
(void) splx(s);
|
||||
return;
|
||||
ispcmd(isp, (XS_T *) arg);
|
||||
break;
|
||||
|
||||
case ADAPTER_REQ_GROW_RESOURCES:
|
||||
/* XXX Not supported. */
|
||||
return;
|
||||
/* Not supported. */
|
||||
break;
|
||||
|
||||
case ADAPTER_REQ_SET_XFER_MODE:
|
||||
if (IS_SCSI(isp)) {
|
||||
|
@ -349,12 +438,12 @@ isprequest(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
|
|||
dflags |= DPARM_WIDE;
|
||||
if (xm->xm_mode & PERIPH_CAP_SYNC)
|
||||
dflags |= DPARM_SYNC;
|
||||
s = splbio();
|
||||
ISP_LOCK(isp);
|
||||
sdp->isp_devparam[xm->xm_target].dev_flags |= dflags;
|
||||
dflags = sdp->isp_devparam[xm->xm_target].dev_flags;
|
||||
sdp->isp_devparam[xm->xm_target].dev_update = 1;
|
||||
isp->isp_update |= (1 << chan->chan_channel);
|
||||
splx(s);
|
||||
ISP_UNLOCK(isp);
|
||||
isp_prt(isp, ISP_LOGDEBUG1,
|
||||
"ispioctl: device flags 0x%x for %d.%d.X",
|
||||
dflags, chan->chan_channel, xm->xm_target);
|
||||
|
@ -366,7 +455,7 @@ isprequest(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
|
|||
}
|
||||
|
||||
static void
|
||||
isp_polled_cmd( struct ispsoftc *isp, XS_T *xs)
|
||||
isp_polled_cmd(struct ispsoftc *isp, XS_T *xs)
|
||||
{
|
||||
int result;
|
||||
int infinite = 0, mswait;
|
||||
|
@ -377,10 +466,13 @@ isp_polled_cmd( struct ispsoftc *isp, XS_T *xs)
|
|||
case CMD_QUEUED:
|
||||
break;
|
||||
case CMD_RQLATER:
|
||||
case CMD_EAGAIN:
|
||||
if (XS_NOERR(xs)) {
|
||||
xs->error = XS_REQUEUE;
|
||||
}
|
||||
case CMD_EAGAIN:
|
||||
if (XS_NOERR(xs)) {
|
||||
xs->error = XS_RESOURCE_SHORTAGE;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CMD_COMPLETE:
|
||||
scsipi_done(xs);
|
||||
|
@ -431,6 +523,20 @@ isp_done(XS_T *xs)
|
|||
"finished command on borrowed time");
|
||||
}
|
||||
XS_CMD_S_CLEAR(xs);
|
||||
/*
|
||||
* Fixup- if we get a QFULL, we need
|
||||
* to set XS_BUSY as the error.
|
||||
*/
|
||||
if (xs->status == SCSI_QUEUE_FULL) {
|
||||
xs->error = XS_BUSY;
|
||||
}
|
||||
if (isp->isp_osinfo.paused) {
|
||||
isp->isp_osinfo.paused = 0;
|
||||
scsipi_channel_timed_thaw(&isp->isp_chanA);
|
||||
if (IS_DUALBUS(isp)) {
|
||||
scsipi_channel_timed_thaw(&isp->isp_chanB);
|
||||
}
|
||||
}
|
||||
scsipi_done(xs);
|
||||
}
|
||||
}
|
||||
|
@ -525,6 +631,74 @@ isp_dog(void *arg)
|
|||
ISP_IUNLOCK(isp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fibre Channel state cleanup thread
|
||||
*/
|
||||
static void
|
||||
isp_create_fc_worker(void *arg)
|
||||
{
|
||||
struct ispsoftc *isp = arg;
|
||||
|
||||
if (kthread_create1(isp_fc_worker, isp, &isp->isp_osinfo.thread,
|
||||
"%s:fc_thrd", isp->isp_name)) {
|
||||
isp_prt(isp, ISP_LOGERR, "unable to create FC worker thread");
|
||||
panic("isp_create_fc_worker");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
isp_fc_worker(void *arg)
|
||||
{
|
||||
void scsipi_run_queue(struct scsipi_channel *);
|
||||
struct ispsoftc *isp = arg;
|
||||
|
||||
for (;;) {
|
||||
int s;
|
||||
|
||||
/*
|
||||
* Note we do *not* use the ISP_LOCK/ISP_UNLOCK macros here.
|
||||
*/
|
||||
s = splbio();
|
||||
while (isp->isp_osinfo.threadwork) {
|
||||
isp->isp_osinfo.threadwork = 0;
|
||||
if (isp_fc_runstate(isp, 10 * 1000000) == 0) {
|
||||
break;
|
||||
}
|
||||
isp->isp_osinfo.threadwork = 1;
|
||||
splx(s);
|
||||
delay(500 * 1000);
|
||||
s = splbio();
|
||||
}
|
||||
if (FCPARAM(isp)->isp_fwstate != FW_READY ||
|
||||
FCPARAM(isp)->isp_loopstate != LOOP_READY) {
|
||||
isp_prt(isp, ISP_LOGINFO, "isp_fc_runstate in vain");
|
||||
isp->isp_osinfo.threadwork = 1;
|
||||
splx(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isp->isp_osinfo.blocked) {
|
||||
isp->isp_osinfo.blocked = 0;
|
||||
isp_prt(isp, /* ISP_LOGDEBUG0 */ ISP_LOGALL, "restarting queues (freeze count %d)", isp->isp_chanA.chan_qfreeze);
|
||||
|
||||
scsipi_channel_thaw(&isp->isp_chanA, 1);
|
||||
}
|
||||
|
||||
if (isp->isp_osinfo.thread == NULL)
|
||||
break;
|
||||
|
||||
(void) tsleep(&isp->isp_osinfo.thread, PRIBIO, "fcclnup", 0);
|
||||
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/* In case parent is waiting for us to exit. */
|
||||
wakeup(&isp->isp_osinfo.thread);
|
||||
|
||||
kthread_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free any associated resources prior to decommissioning and
|
||||
* set the card to a known state (so it doesn't wake up and kick
|
||||
|
@ -547,7 +721,7 @@ int
|
|||
isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
|
||||
{
|
||||
int bus, tgt;
|
||||
int s = splbio();
|
||||
|
||||
switch (cmd) {
|
||||
case ISPASYNC_NEW_TGT_PARAMS:
|
||||
if (IS_SCSI(isp) && isp->isp_dblev) {
|
||||
|
@ -572,37 +746,61 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
|
|||
xm.xm_mode |= PERIPH_CAP_WIDE16;
|
||||
if (flags & DPARM_TQING)
|
||||
xm.xm_mode |= PERIPH_CAP_TQING;
|
||||
scsipi_async_event(
|
||||
bus ? (&isp->isp_osinfo._chan_b) : (&isp->isp_osinfo._chan),
|
||||
ASYNC_EVENT_XFER_MODE,
|
||||
&xm);
|
||||
scsipi_async_event(bus? &isp->isp_chanB : &isp->isp_chanA,
|
||||
ASYNC_EVENT_XFER_MODE, &xm);
|
||||
break;
|
||||
}
|
||||
case ISPASYNC_BUS_RESET:
|
||||
if (arg)
|
||||
bus = *((int *) arg);
|
||||
else
|
||||
bus = 0;
|
||||
bus = *((int *) arg);
|
||||
scsipi_async_event(bus? &isp->isp_chanB : &isp->isp_chanA,
|
||||
ASYNC_EVENT_RESET, NULL);
|
||||
isp_prt(isp, ISP_LOGINFO, "SCSI bus %d reset detected", bus);
|
||||
break;
|
||||
case ISPASYNC_LIP:
|
||||
/*
|
||||
* Don't do queue freezes or blockage until we have the
|
||||
* thread running that can unfreeze/unblock us.
|
||||
*/
|
||||
if (isp->isp_osinfo.blocked == 0) {
|
||||
if (isp->isp_osinfo.thread) {
|
||||
isp->isp_osinfo.blocked = 1;
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
}
|
||||
}
|
||||
isp_prt(isp, ISP_LOGINFO, "LIP Received");
|
||||
break;
|
||||
case ISPASYNC_LOOP_RESET:
|
||||
/*
|
||||
* Don't do queue freezes or blockage until we have the
|
||||
* thread running that can unfreeze/unblock us.
|
||||
*/
|
||||
if (isp->isp_osinfo.blocked == 0) {
|
||||
if (isp->isp_osinfo.thread) {
|
||||
isp->isp_osinfo.blocked = 1;
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
}
|
||||
}
|
||||
isp_prt(isp, ISP_LOGINFO, "Loop Reset Received");
|
||||
break;
|
||||
case ISPASYNC_LOOP_DOWN:
|
||||
/*
|
||||
* Hopefully we get here in time to minimize the number
|
||||
* of commands we are firing off that are sure to die.
|
||||
* Don't do queue freezes or blockage until we have the
|
||||
* thread running that can unfreeze/unblock us.
|
||||
*/
|
||||
scsipi_channel_freeze(&isp->isp_osinfo._chan, 1);
|
||||
if (IS_DUALBUS(isp))
|
||||
scsipi_channel_freeze(&isp->isp_osinfo._chan_b, 1);
|
||||
if (isp->isp_osinfo.blocked == 0) {
|
||||
if (isp->isp_osinfo.thread) {
|
||||
isp->isp_osinfo.blocked = 1;
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
}
|
||||
}
|
||||
isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
|
||||
break;
|
||||
case ISPASYNC_LOOP_UP:
|
||||
callout_reset(&isp->isp_osinfo._restart, 1,
|
||||
scsipi_channel_timed_thaw, &isp->isp_osinfo._chan);
|
||||
if (IS_DUALBUS(isp)) {
|
||||
callout_reset(&isp->isp_osinfo._restart, 1,
|
||||
scsipi_channel_timed_thaw,
|
||||
&isp->isp_osinfo._chan_b);
|
||||
}
|
||||
/*
|
||||
* Let the subsequent ISPASYNC_CHANGE_NOTIFY invoke
|
||||
* the FC worker thread. When the FC worker thread
|
||||
* is done, let *it* call scsipi_channel_thaw...
|
||||
*/
|
||||
isp_prt(isp, ISP_LOGINFO, "Loop UP");
|
||||
break;
|
||||
case ISPASYNC_PROMENADE:
|
||||
|
@ -632,6 +830,30 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
|
|||
isp_prt(isp, ISP_LOGINFO,
|
||||
"Name Server Database Changed");
|
||||
}
|
||||
|
||||
/*
|
||||
* We can set blocked here because we know it's now okay
|
||||
* to try and run isp_fc_runstate (in order to build loop
|
||||
* state). But we don't try and freeze the midlayer's queue
|
||||
* if we have no thread that we can wake to later unfreeze
|
||||
* it.
|
||||
*/
|
||||
if (isp->isp_osinfo.blocked == 0) {
|
||||
isp->isp_osinfo.blocked = 1;
|
||||
if (isp->isp_osinfo.thread) {
|
||||
scsipi_channel_freeze(&isp->isp_chanA, 1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Note that we have work for the thread to do, and
|
||||
* if the thread is here already, wake it up.
|
||||
*/
|
||||
isp->isp_osinfo.threadwork++;
|
||||
if (isp->isp_osinfo.thread) {
|
||||
wakeup(&isp->isp_osinfo.thread);
|
||||
} else {
|
||||
isp_prt(isp, ISP_LOGDEBUG1, "no FC thread yet");
|
||||
}
|
||||
break;
|
||||
case ISPASYNC_FABRIC_DEV:
|
||||
{
|
||||
|
@ -750,7 +972,6 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
(void) splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: isp_netbsd.h,v 1.42 2001/05/16 21:41:52 mjacob Exp $ */
|
||||
/* $NetBSD: isp_netbsd.h,v 1.43 2001/05/25 21:45:55 mjacob Exp $ */
|
||||
/*
|
||||
* This driver, which is contained in NetBSD in the files:
|
||||
*
|
||||
|
@ -71,6 +71,7 @@
|
|||
#include <sys/buf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/kthread.h>
|
||||
|
||||
|
||||
#include <dev/scsipi/scsi_all.h>
|
||||
|
@ -83,8 +84,8 @@
|
|||
#include "opt_isp.h"
|
||||
|
||||
|
||||
#define ISP_PLATFORM_VERSION_MAJOR 1
|
||||
#define ISP_PLATFORM_VERSION_MINOR 1
|
||||
#define ISP_PLATFORM_VERSION_MAJOR 2
|
||||
#define ISP_PLATFORM_VERSION_MINOR 0
|
||||
|
||||
struct isposinfo {
|
||||
struct device _dev;
|
||||
|
@ -95,10 +96,12 @@ struct isposinfo {
|
|||
int mboxwaiting;
|
||||
u_int32_t islocked;
|
||||
u_int32_t onintstack;
|
||||
unsigned int : 28,
|
||||
unsigned int : 26,
|
||||
loop_checked : 1,
|
||||
mbox_wanted : 1,
|
||||
mbox_locked : 1,
|
||||
no_mbox_ints : 1,
|
||||
paused : 1,
|
||||
blocked : 1;
|
||||
union {
|
||||
u_int64_t _wwn;
|
||||
|
@ -106,12 +109,14 @@ struct isposinfo {
|
|||
#define wwn_seed un._wwn
|
||||
#define discovered un._discovered
|
||||
} un;
|
||||
TAILQ_HEAD(, scsipi_xfer) waitq;
|
||||
struct callout _restart;
|
||||
u_int32_t threadwork;
|
||||
struct proc *thread;
|
||||
};
|
||||
#define ISP_MUSTPOLL(isp) \
|
||||
(isp->isp_osinfo.onintstack || isp->isp_osinfo.no_mbox_ints)
|
||||
|
||||
#define HANDLE_LOOPSTATE_IN_OUTER_LAYERS 1
|
||||
|
||||
/*
|
||||
* Required Macros/Defines
|
||||
*/
|
||||
|
@ -277,6 +282,9 @@ struct isposinfo {
|
|||
*/
|
||||
#define isp_name isp_osinfo._dev.dv_xname
|
||||
#define isp_unit isp_osinfo._dev.dv_unit
|
||||
#define isp_chanA isp_osinfo._chan
|
||||
#define isp_chanB isp_osinfo._chan_b
|
||||
|
||||
|
||||
/*
|
||||
* Driver prototypes..
|
||||
|
|
Loading…
Reference in New Issue