Merge my bjh21-wd33c93 branch. This improves message handling in general

and sync negotiation in particular.  Tested on sgimips (thanks to
Manuel Bouyer) and acorn26 (with my still-unfinished driver for the Acorn
SCSI Expansion Card).
This commit is contained in:
bjh21 2006-09-26 22:45:25 +00:00
parent a63ad7b671
commit 334ef0cbc9
2 changed files with 104 additions and 74 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: wd33c93.c,v 1.7 2006/09/05 17:31:31 rumble Exp $ */
/* $NetBSD: wd33c93.c,v 1.8 2006/09/26 22:45:25 bjh21 Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wd33c93.c,v 1.7 2006/09/05 17:31:31 rumble Exp $");
__KERNEL_RCSID(0, "$NetBSD: wd33c93.c,v 1.8 2006/09/26 22:45:25 bjh21 Exp $");
#include "opt_ddb.h"
@ -208,7 +208,6 @@ wd33c93_attach(struct wd33c93_softc *dev)
callout_init(&dev->sc_watchdog);
dev->sc_minsync = 200/4; /* Min SCSI sync rate in 4ns units */
dev->sc_maxoffset = SBIC_SYN_MAX_OFFSET; /* Max Sync Offset */
/*
@ -224,6 +223,11 @@ wd33c93_attach(struct wd33c93_softc *dev)
dev->sc_cfflags = device_cfdata(&dev->sc_dev)->cf_flags;
wd33c93_init(dev);
printf(": %s revision %d, %d.%d MHz, SCSI ID %d\n",
wd33c93_chip_names[dev->sc_chip], dev->sc_rev,
dev->sc_clkfreq / 10, dev->sc_clkfreq % 10,
dev->sc_channel.chan_id);
dev->sc_child = config_found(&dev->sc_dev, &dev->sc_channel,
scsiprint);
scsipi_adapter_delref(&dev->sc_adapter);
@ -269,11 +273,11 @@ wd33c93_init(struct wd33c93_softc *dev)
* SS = Bitmask to diable Sync negotiation
*/
ti->flags = T_NEED_RESET;
if (dev->sc_minsync == 0 || (dev->sc_cfflags & (1<<(i+8))))
if (dev->sc_cfflags & (1<<(i+8)))
ti->flags |= T_NOSYNC;
if (dev->sc_cfflags & (1<<i) || wd33c93_nodisc)
ti->flags |= T_NODISC;
ti->period = dev->sc_minsync;
ti->period = dev->sc_syncperiods[0];
ti->offset = 0;
}
}
@ -281,7 +285,7 @@ wd33c93_init(struct wd33c93_softc *dev)
void
wd33c93_reset(struct wd33c93_softc *dev)
{
u_int my_id, s;
u_int my_id, s, div, i;
u_char csr, reg;
SET_SBIC_cmd(dev, SBIC_CMD_ABORT);
@ -293,12 +297,29 @@ wd33c93_reset(struct wd33c93_softc *dev)
(*dev->sc_reset)(dev);
my_id = dev->sc_channel.chan_id & SBIC_ID_MASK;
if (dev->sc_clkfreq < 110)
/*
* Choose a suitable clock divisor and work out the resulting
* sync transfer periods in 4ns units.
*/
if (dev->sc_clkfreq < 110) {
my_id |= SBIC_ID_FS_8_10;
else if (dev->sc_clkfreq < 160)
div = 2;
} else if (dev->sc_clkfreq < 160) {
my_id |= SBIC_ID_FS_12_15;
else if (dev->sc_clkfreq < 210)
div = 3;
} else if (dev->sc_clkfreq < 210) {
my_id |= SBIC_ID_FS_16_20;
div = 4;
} else
panic("wd33c93: invalid clock speed %d", dev->sc_clkfreq);
for (i = 0; i < 7; i++)
dev->sc_syncperiods[i] =
(i + 2) * div * 1250 / dev->sc_clkfreq;
SBIC_DEBUG(SYNC, ("available sync periods: %d %d %d %d %d %d %d\n",
dev->sc_syncperiods[0], dev->sc_syncperiods[1],
dev->sc_syncperiods[2], dev->sc_syncperiods[3],
dev->sc_syncperiods[4], dev->sc_syncperiods[5],
dev->sc_syncperiods[6]));
/* Enable advanced features */
#if 1
@ -346,10 +367,6 @@ wd33c93_reset(struct wd33c93_softc *dev)
dev->sc_state = SBIC_IDLE;
splx(s);
printf(": %s SCSI, rev=%d, target %d\n",
wd33c93_chip_names[dev->sc_chip], dev->sc_rev,
dev->sc_channel.chan_id);
}
void
@ -557,9 +574,7 @@ wd33c93_scsi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, void
struct scsipi_xfer_mode *xm = arg;
ti = &dev->sc_tinfo[xm->xm_target];
ti->flags &= ~(T_NEGOTIATE|T_SYNCMODE);
ti->period = 0;
ti->offset = 0;
ti->flags &= ~T_WANTSYNC;
if ((dev->sc_cfflags & (1<<(xm->xm_target+16))) == 0 &&
(xm->xm_mode & PERIPH_CAP_TQING) && !wd33c93_notags)
@ -567,19 +582,21 @@ wd33c93_scsi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, void
else
ti->flags &= ~T_TAG;
SBIC_DEBUG(SYNC, ("wd33c93_scsi_request: "
"target %d: scsipi requested %s\n", xm->xm_target,
(xm->xm_mode & PERIPH_CAP_SYNC) ? "sync" : "async"));
if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
(ti->flags & T_NOSYNC) == 0 && dev->sc_minsync != 0) {
SBIC_DEBUG(SYNC, ("target %d: sync negotiation\n",
xm->xm_target));
ti->flags |= T_NEGOTIATE;
ti->period = dev->sc_minsync;
}
(ti->flags & T_NOSYNC) == 0)
ti->flags |= T_WANTSYNC;
/*
* If we're not going to negotiate, send the notification
* now, since it won't happen later.
*/
if ((ti->flags & T_NEGOTIATE) == 0)
if (!(ti->flags & T_WANTSYNC) == !(ti->flags & T_SYNCMODE))
wd33c93_update_xfer_mode(dev, xm->xm_target);
else
ti->flags |= T_NEGOTIATE;
return;
}
@ -1021,16 +1038,25 @@ wd33c93_selectbus(struct wd33c93_softc *dev, struct wd33c93_acb *acb)
if (ti->flags & T_NEGOTIATE) {
/* Inititae a SDTR message */
SBIC_DEBUG(SYNC, ("Sending SDTR to target %d\n", id));
ti->period = dev->sc_minsync;
ti->offset = dev->sc_maxoffset;
if (ti->flags & T_WANTSYNC) {
ti->period = dev->sc_syncperiods[0];
ti->offset = dev->sc_maxoffset;
} else {
ti->period = 0;
ti->offset = 0;
}
/* Send Sync negotiation message */
dev->sc_omsg[0] = MSG_IDENTIFY(lun, 0); /* No Disc */
dev->sc_omsg[1] = MSG_EXTENDED;
dev->sc_omsg[2] = MSG_EXT_SDTR_LEN;
dev->sc_omsg[3] = MSG_EXT_SDTR;
dev->sc_omsg[4] = dev->sc_minsync;
dev->sc_omsg[5] = dev->sc_maxoffset;
if (ti->flags & T_WANTSYNC) {
dev->sc_omsg[4] = dev->sc_syncperiods[0];
dev->sc_omsg[5] = dev->sc_maxoffset;
} else {
dev->sc_omsg[4] = 0;
dev->sc_omsg[5] = 0;
}
wd33c93_xfout(dev, 6, dev->sc_omsg);
dev->sc_msgout |= SEND_SDTR; /* may be rejected */
dev->sc_flags |= SBICF_SYNCNEGO;
@ -1421,6 +1447,9 @@ wd33c93_msgin_phase(struct wd33c93_softc *dev, int reselect)
SBIC_WAIT(dev, SBIC_ASR_INT, 0);
GET_SBIC_csr(dev, csr);
if (__verify_msg_format(dev->sc_imsg, len))
break; /* Complete message recieved */
/*
* Clear ACK, and wait for the interrupt
* for the next byte or phase change
@ -1428,15 +1457,19 @@ wd33c93_msgin_phase(struct wd33c93_softc *dev, int reselect)
SET_SBIC_cmd(dev, SBIC_CMD_CLR_ACK);
SBIC_WAIT(dev, SBIC_ASR_INT, 0);
if (__verify_msg_format(dev->sc_imsg, len))
break; /* Complete message recieved */
GET_SBIC_csr(dev, csr);
} while (len < SBIC_MAX_MSGLEN);
if (__verify_msg_format(dev->sc_imsg, len))
wd33c93_msgin(dev, dev->sc_imsg, len);
/*
* Clear ACK, and wait for the interrupt
* for the phase change
*/
SET_SBIC_cmd(dev, SBIC_CMD_CLR_ACK);
SBIC_WAIT(dev, SBIC_ASR_INT, 0);
/* Should still have one CSR to read */
return SBIC_STATE_RUNNING;
}
@ -1577,21 +1610,18 @@ void wd33c93_msgin(struct wd33c93_softc *dev, u_char *msgaddr, int msglen)
if (msgaddr[1] != 3)
goto reject;
ti->period = MAX(msgaddr[3], dev->sc_minsync);
ti->period =
MAX(msgaddr[3], dev->sc_syncperiods[0]);
ti->offset = MIN(msgaddr[4], dev->sc_maxoffset);
if (!(ti->flags & T_WANTSYNC))
ti->period = ti->offset = 0;
ti->flags &= ~T_NEGOTIATE;
if (dev->sc_minsync == 0 || ti->period > 124)
ti->offset = ti->period = 0;
if (ti->offset == 0)
ti->flags &= ~T_SYNCMODE; /* Async */
else {
int p;
p = wd33c93_stp2div(dev, ti->period);
ti->period = wd33c93_div2stp(dev, p);
else
ti->flags |= T_SYNCMODE; /* Sync */
}
if ((dev->sc_flags&SBICF_SYNCNEGO) == 0)
/* target initiated negotiation */
@ -1607,8 +1637,8 @@ void wd33c93_msgin(struct wd33c93_softc *dev, u_char *msgaddr, int msglen)
break;
case MSG_EXT_WDTR:
SBIC_DEBUG(MSGS, ("msgin: EXT_WDTR ignored"));
break;
SBIC_DEBUG(MSGS, ("msgin: EXT_WDTR rejected"));
goto reject;
default:
scsipi_printaddr(acb->xs->xs_periph);
@ -1719,11 +1749,19 @@ wd33c93_msgout(struct wd33c93_softc *dev)
dev->sc_omsg[0] = MSG_EXTENDED;
dev->sc_omsg[1] = MSG_EXT_SDTR_LEN;
dev->sc_omsg[2] = MSG_EXT_SDTR;
dev->sc_omsg[3] = ti->period;
dev->sc_omsg[4] = ti->offset;
if (ti->flags & T_WANTSYNC) {
dev->sc_omsg[3] = ti->period;
dev->sc_omsg[4] = ti->offset;
} else {
dev->sc_omsg[3] = 0;
dev->sc_omsg[4] = 0;
}
dev->sc_omsglen = 5;
if ((dev->sc_flags & SBICF_SYNCNEGO) == 0) {
ti->flags |= T_SYNCMODE;
if (ti->flags & T_WANTSYNC)
ti->flags |= T_SYNCMODE;
else
ti->flags &= ~T_SYNCMODE;
wd33c93_setsync(dev, ti);
}
break;
@ -2120,6 +2158,9 @@ wd33c93_reselect(struct wd33c93_softc *dev, int target, int lun, int tag_type, i
dev->sc_nexus = acb;
dev->sc_state = SBIC_CONNECTED;
if (!wd33c93_dmaok(dev, acb->xs))
dev->sc_flags |= SBICF_NODMA;
/* Do an implicit RESTORE POINTERS. */
dev->sc_daddr = acb->daddr;
dev->sc_dleft = acb->dleft;
@ -2159,13 +2200,17 @@ wd33c93_update_xfer_mode(struct wd33c93_softc *sc, int target)
if ((ti->flags & (T_NODISC|T_TAG)) == T_TAG)
xm.xm_mode |= PERIPH_CAP_TQING;
SBIC_DEBUG(SYNC, ("wd33c93_update_xfer_mode: reporting target %d %s\n",
xm.xm_target,
(xm.xm_mode & PERIPH_CAP_SYNC) ? "sync" : "async"));
scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
}
/*
* Convert SCSI Transfer Period Factor (in 4ns units) to the divisor
* value used by the WD33c93 controller.
* Calculate SCSI Tranfser Period Factor (4ns units each) from the
* WD33c93 divisor value
*
* cycle = DIV / (2 * CLK)
* DIV = FS + 2
@ -2174,39 +2219,25 @@ wd33c93_update_xfer_mode(struct wd33c93_softc *sc, int target)
int
wd33c93_div2stp(struct wd33c93_softc *dev, int div)
{
unsigned int fs;
GET_SBIC_myid(dev, fs);
fs = (fs >> 6) + 2; /* DIV */
fs = (fs * 10000) / (dev->sc_clkfreq << 1); /* Cycle, in ns */
if (div < 2)
div = 8; /* map to Cycles */
return ((fs * div) >> 2); /* in 4 ns units */
return dev->sc_syncperiods[div - 2];
}
/*
* Calculate SCSI Tranfser Period Factor (4ns units each) from the
* WD33c93 divisor value
* Convert SCSI Transfer Period Factor (in 4ns units) to the divisor
* value used by the WD33c93 controller.
*/
int
wd33c93_stp2div(struct wd33c93_softc *dev, int stp)
{
unsigned fs, div;
unsigned i;
/* Just the inverse of the above */
GET_SBIC_myid(dev, fs);
fs = (fs >> 6) + 2; /* DIV */
fs = (fs * 10000) / (dev->sc_clkfreq << 1); /* Cycle, in ns */
div = stp << 2; /* in ns units */
div = div / fs; /* in Cycles */
if (div < 2)
return(2);
/* verify rounding */
if (wd33c93_div2stp(dev, div) < stp)
div++;
return((div >= 8) ? 0 : div);
for (i = 0; i < 7; i++)
if (dev->sc_syncperiods[i] >= stp)
return (i == 6 ? 0 : i + 2);
return 0; /* XXX we can't slow down far enough */
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: wd33c93var.h,v 1.1 2006/08/26 22:06:37 bjh21 Exp $ */
/* $NetBSD: wd33c93var.h,v 1.2 2006/09/26 22:45:25 bjh21 Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@ -88,7 +88,6 @@ struct wd33c93_linfo {
time_t last_used;
int lun;
int used; /* # slots in use */
int avail; /* where to start scanning */
u_char state;
#define L_STATE_IDLE 0
#define L_STATE_BUSY 1
@ -109,9 +108,9 @@ struct wd33c93_tinfo {
#define T_NOSYNC 0x10 /* Force ASYNC mode */
#define T_NODISC 0x20 /* Don't allow disconnect */
#define T_TAG 0x40 /* Turn on TAG QUEUEs */
#define T_WANTSYNC 0x80 /* Negotiatious should aim for sync */
u_char period; /* Period suggestion */
u_char offset; /* Offset suggestion */
u_char nextag; /* Next available tag */
struct wd33c93_linfo *lun[SBIC_NLUN]; /* LUN list for this target */
} tinfo_t;
@ -169,8 +168,8 @@ struct wd33c93_softc {
int sc_rev; /* Chip revision */
int sc_cfflags; /* Copy of config flags */
int sc_maxxfer; /* Maximum transfer size */
int sc_minsync; /* Minimum sync period (4ns units) */
int sc_maxoffset; /* Maximum sync ofset (bytes) */
uint8_t sc_maxoffset; /* Maximum sync ofset (bytes) */
uint8_t sc_syncperiods[7]; /* Sync transfer periods (4ns units) */
int (*sc_dmasetup) (struct wd33c93_softc *, caddr_t *,
size_t *, int, size_t *);