summaryrefslogtreecommitdiffstats
path: root/sys/dev/aic
diff options
context:
space:
mode:
authorluoqi <luoqi@FreeBSD.org>1999-12-04 22:15:02 +0000
committerluoqi <luoqi@FreeBSD.org>1999-12-04 22:15:02 +0000
commitd59911ee914d7ea0e3d9d8905a0875d17d832fb7 (patch)
tree0ed7d534db349d17beed26354edc1b1fe690a2f4 /sys/dev/aic
parent19f112ec6a1374ee12f2d3e22c95f5dea3d22043 (diff)
downloadFreeBSD-src-d59911ee914d7ea0e3d9d8905a0875d17d832fb7.zip
FreeBSD-src-d59911ee914d7ea0e3d9d8905a0875d17d832fb7.tar.gz
Disconnect and tagged queueing now really work. Also fix a bug that's
causing problems to slow devices.
Diffstat (limited to 'sys/dev/aic')
-rw-r--r--sys/dev/aic/aic.c208
-rw-r--r--sys/dev/aic/aic_isa.c5
-rw-r--r--sys/dev/aic/aicvar.h3
3 files changed, 115 insertions, 101 deletions
diff --git a/sys/dev/aic/aic.c b/sys/dev/aic/aic.c
index 341c7e1..9cb2fa9 100644
--- a/sys/dev/aic/aic.c
+++ b/sys/dev/aic/aic.c
@@ -56,6 +56,7 @@ static void aic_start __P((struct aic_softc *aic));
static void aic_select __P((struct aic_softc *aic));
static void aic_selected __P((struct aic_softc *aic));
static void aic_reselected __P((struct aic_softc *aic));
+static void aic_reconnect __P((struct aic_softc *aic, int tag));
static void aic_cmd __P((struct aic_softc *aic));
static void aic_msgin __P((struct aic_softc *aic));
static void aic_handle_msgin __P((struct aic_softc *aic));
@@ -351,6 +352,8 @@ aic_start(struct aic_softc *aic)
}
}
+ CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_start: idle\n"));
+
aic_outb(aic, SIMODE0, ENSELDI);
aic_outb(aic, SIMODE1, ENSCSIRST);
aic_outb(aic, SCSISEQ, ENRESELI);
@@ -404,14 +407,12 @@ aic_selected(struct aic_softc *aic)
if ((ti->flags & TINFO_TAG_ENB) != 0 &&
(ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
aic->msg_outq |= AIC_MSG_TAG_Q;
+ else
+ ti->lubusy |= 1 << scb->lun;
if ((ti->flags & TINFO_SDTR_NEGO) != 0)
aic->msg_outq |= AIC_MSG_SDTR;
}
- /* mark target/lun busy only for untagged operations */
- if ((aic->msg_outq & AIC_MSG_TAG_Q) == 0)
- ti->lubusy |= 1 << scb->lun;
-
aic_outb(aic, CLRSINT0, CLRSELDO);
aic_outb(aic, CLRSINT1, CLRBUSFREE);
aic_outb(aic, SCSISEQ, ENAUTOATNP);
@@ -428,7 +429,6 @@ static void
aic_reselected(struct aic_softc *aic)
{
u_int8_t selid;
- struct aic_tinfo *ti;
CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reselected\n"));
@@ -442,9 +442,10 @@ aic_reselected(struct aic_softc *aic)
aic->nexus = NULL;
}
- selid = aic_inb(aic, SELID) & SCSI_ID_MASK;
+ selid = aic_inb(aic, SELID) & ~(1 << aic->initiator);
if (selid & (selid - 1)) {
/* this should never have happened */
+ printf("aic_reselected: invalid selid %x\n", selid);
aic_reset(aic, /*initiate_reset*/TRUE);
return;
}
@@ -452,14 +453,13 @@ aic_reselected(struct aic_softc *aic)
aic->state = AIC_RESELECTED;
aic->target = ffs(selid) - 1;
aic->lun = -1;
- ti = &aic->tinfo[aic->target];
aic_outb(aic, CLRSINT0, CLRSELDI);
aic_outb(aic, CLRSINT1, CLRBUSFREE);
aic_outb(aic, SIMODE0, 0);
aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
aic_outb(aic, SCSISEQ, ENAUTOATNP);
- aic_outb(aic, SCSIRATE, ti->scsirate);
+ aic_outb(aic, SCSIRATE, aic->tinfo[aic->target].scsirate);
}
/*
@@ -482,13 +482,46 @@ aic_sched_msgout(struct aic_softc *aic, u_int8_t msg)
static __inline int
aic_spiordy(struct aic_softc *aic)
{
- int spincount = 100;
- u_int8_t spiordy = 0;
-
- while (spincount-- && !(aic_inb(aic, DMASTAT) & INTSTAT) &&
- !(spiordy = aic_inb(aic, SSTAT0) & SPIORDY))
+ while (!(aic_inb(aic, DMASTAT) & INTSTAT) &&
+ !(aic_inb(aic, SSTAT0) & SPIORDY))
;
- return (spiordy);
+ return !(aic_inb(aic, DMASTAT) & INTSTAT);
+}
+
+/*
+ * Reestablish a disconnected nexus.
+ */
+void
+aic_reconnect(struct aic_softc *aic, int tag)
+{
+ struct aic_scb *scb;
+ struct ccb_hdr *ccb_h;
+
+ CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reconnect\n"));
+
+ /* Find the nexus */
+ TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe) {
+ scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
+ if (scb->target == aic->target && scb->lun == aic->lun &&
+ (tag == -1 || scb->tag == tag))
+ break;
+ }
+
+ /* ABORT if nothing is found */
+ if (!ccb_h) {
+ if (tag == -1)
+ aic_sched_msgout(aic, MSG_ABORT);
+ else
+ aic_sched_msgout(aic, MSG_ABORT_TAG);
+ xpt_async(AC_UNSOL_RESEL, aic->path, NULL);
+ return;
+ }
+
+ /* Reestablish the nexus */
+ TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
+ aic->nexus = scb;
+ scb->flags &= ~SCB_DISCONNECTED;
+ aic->state = AIC_HASNEXUS;
}
/*
@@ -544,7 +577,7 @@ aic_msgin(struct aic_softc *aic)
aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
}
msglen += 2;
- } else if (aic->msg_buf[0] & 0x20)
+ } else if (aic->msg_buf[0] >= 0x20 && aic->msg_buf[0] <= 0x2f)
msglen = 2;
else
msglen = 1;
@@ -576,51 +609,24 @@ aic_handle_msgin(struct aic_softc *aic)
struct ccb_trans_settings neg;
if (aic->state == AIC_RESELECTED) {
- int tag;
-
- ti = &aic->tinfo[aic->target];
- /*
- * We expect to see an IDENTIFY message, possibly followed
- * by a SIMPLE_Q_TAG message.
- */
- if (MSG_ISIDENTIFY(aic->msg_buf[0])) {
- aic->lun = aic->msg_buf[0] & MSG_IDENTIFY_LUNMASK;
- if (ti->flags & TINFO_TAG_ENB)
- return;
- else
- tag = -1;
- } else if (aic->msg_buf[0] != MSG_SIMPLE_Q_TAG) {
- tag = aic->msg_buf[1];
- } else {
+ if (!MSG_ISIDENTIFY(aic->msg_buf[0])) {
aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
return;
}
+ aic->lun = aic->msg_buf[0] & MSG_IDENTIFY_LUNMASK;
+ if (aic->tinfo[aic->target].lubusy & (1 << aic->lun))
+ aic_reconnect(aic, -1);
+ else
+ aic->state = AIC_RECONNECTING;
+ return;
+ }
- /* Find the nexus */
- TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe) {
- scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
- if (ccb_h->target_id == aic->target &&
- ccb_h->target_lun == aic->lun &&
- (tag == -1 || scb->tag == tag))
- break;
- }
-
- /* ABORT if nothing is found */
- if (!ccb_h) {
- if (tag == -1)
- aic_sched_msgout(aic, MSG_ABORT);
- else
- aic_sched_msgout(aic, MSG_ABORT_TAG);
- xpt_async(AC_UNSOL_RESEL, ccb_h->path, NULL);
+ if (aic->state == AIC_RECONNECTING) {
+ if (aic->msg_buf[0] != MSG_SIMPLE_Q_TAG) {
+ aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
return;
}
-
- /* Reestablish the nexus */
- TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
- aic->nexus = scb;
- scb->flags &= ~SCB_DISCONNECTED;
- aic->state = AIC_HASNEXUS;
- CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("reconnected\n"));
+ aic_reconnect(aic, aic->msg_buf[1]);
return;
}
@@ -630,7 +636,6 @@ aic_handle_msgin(struct aic_softc *aic)
scb = aic->nexus;
ccb_h = &scb->ccb->ccb_h;
csio = &scb->ccb->csio;
- ccb_h->status &= ~CAM_STATUS_MASK;
if ((scb->flags & SCB_SENSE) != 0) {
/* auto REQUEST SENSE command */
scb->flags &= ~SCB_SENSE;
@@ -704,11 +709,11 @@ aic_handle_msgin(struct aic_softc *aic)
case MSG_DISCONNECT:
scb = aic->nexus;
ccb_h = &scb->ccb->ccb_h;
- TAILQ_INSERT_HEAD(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
+ TAILQ_INSERT_TAIL(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
scb->flags |= SCB_DISCONNECTED;
- ti = &aic->tinfo[scb->target];
aic->flags |= AIC_BUSFREE_OK;
- CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("disconnected\n"));
+ aic->nexus = NULL;
+ CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, ("disconnected\n"));
break;
case MSG_MESSAGE_REJECT:
switch (aic->msg_outq & -aic->msg_outq) {
@@ -794,7 +799,7 @@ aic_msgout(struct aic_softc *aic)
ti = &aic->tinfo[scb->target];
aic->msg_buf[0] = MSG_IDENTIFY(scb->lun,
(ti->flags & TINFO_DISC_ENB) &&
- (ccb->ccb_h.flags & CAM_DIS_DISCONNECT));
+ !(ccb->ccb_h.flags & CAM_DIS_DISCONNECT));
aic->msg_len = 1;
break;
case AIC_MSG_TAG_Q:
@@ -984,6 +989,8 @@ aic_cmd(struct aic_softc *aic)
struct aic_scb *scb = aic->nexus;
struct scsi_request_sense sense_cmd;
+ CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_cmd\n"));
+
if (scb->flags & SCB_SENSE) {
/* autosense request */
sense_cmd.opcode = REQUEST_SENSE;
@@ -998,6 +1005,7 @@ aic_cmd(struct aic_softc *aic)
scb->data_len = scb->ccb->csio.sense_len;
}
+ aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
aic_outb(aic, DMACNTRL0, ENDMA|WRITE);
aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
aic_outsw(aic, DMADATA, (u_int16_t *)scb->cmd_ptr,
@@ -1006,6 +1014,7 @@ aic_cmd(struct aic_softc *aic)
(aic_inb(aic, DMASTAT) & INTSTAT) == 0)
;
aic_outb(aic, SXFRCTL0, CHEN);
+ aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
}
/*
@@ -1034,8 +1043,10 @@ aic_done(struct aic_softc *aic, struct aic_scb *scb)
scb->target,
CAM_LUN_WILDCARD);
- if (error == CAM_REQ_CMP)
+ if (error == CAM_REQ_CMP) {
xpt_async(AC_SENT_BDR, path, NULL);
+ xpt_free_path(path);
+ }
ccb_h = TAILQ_FIRST(&aic->pending_ccbs);
while (ccb_h != NULL) {
@@ -1043,7 +1054,7 @@ aic_done(struct aic_softc *aic, struct aic_scb *scb)
pending_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
if (ccb_h->target_id == scb->target) {
- ccb_h->status = CAM_BDR_SENT;
+ ccb_h->status |= CAM_BDR_SENT;
ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
TAILQ_REMOVE(&aic->pending_ccbs,
&pending_scb->ccb->ccb_h, sim_links.tqe);
@@ -1062,7 +1073,7 @@ aic_done(struct aic_softc *aic, struct aic_scb *scb)
nexus_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
if (ccb_h->target_id == scb->target) {
- ccb_h->status = CAM_BDR_SENT;
+ ccb_h->status |= CAM_BDR_SENT;
ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
TAILQ_REMOVE(&aic->nexus_ccbs,
&nexus_scb->ccb->ccb_h, sim_links.tqe);
@@ -1081,7 +1092,6 @@ aic_done(struct aic_softc *aic, struct aic_scb *scb)
if (aic->nexus == scb) {
aic->nexus = NULL;
- aic->state = AIC_IDLE;
}
aic_free_scb(aic, scb);
xpt_done(ccb);
@@ -1105,7 +1115,7 @@ aic_timeout(void *arg)
printf("ccb %p - timed out", ccb);
if (aic->nexus && aic->nexus != scb)
printf(", nexus %p", aic->nexus->ccb);
- printf(", phase %x\n", aic_inb(aic, SCSISIGI));
+ printf(", phase 0x%x, state %d\n", aic_inb(aic, SCSISIGI), aic->state);
s = splcam();
@@ -1140,7 +1150,6 @@ aic_timeout(void *arg)
aic_sched_msgout(aic, MSG_BUS_DEV_RESET);
} else {
if (aic->nexus == scb) {
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
aic_done(aic, scb);
}
@@ -1186,7 +1195,7 @@ aic_intr(void *arg)
return;
}
- if (aic->state != AIC_HASNEXUS) {
+ if (aic->state <= AIC_SELECTING) {
if ((sstat0 & SELDI) != 0) {
aic_reselected(aic);
aic_outb(aic, DMACNTRL0, INTEN);
@@ -1210,6 +1219,41 @@ aic_intr(void *arg)
}
}
+ if ((sstat1 & BUSFREE) != 0) {
+ aic_outb(aic, SCSISEQ, 0);
+ aic_outb(aic, CLRSINT0, sstat0);
+ aic_outb(aic, CLRSINT1, sstat1);
+ if ((scb = aic->nexus)) {
+ if ((aic->flags & AIC_BUSFREE_OK) == 0) {
+ ccb = scb->ccb;
+ ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
+ aic_done(aic, scb);
+ } else if (scb->flags & SCB_DEVICE_RESET) {
+ ccb = scb->ccb;
+ if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
+ xpt_async(AC_SENT_BDR,
+ ccb->ccb_h.path, NULL);
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ } else
+ ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
+ aic_done(aic, scb);
+ } else if (scb->flags & SCB_SENSE) {
+ /* autosense request */
+ aic->flags &= ~AIC_BUSFREE_OK;
+ aic->tinfo[scb->target].lubusy &=
+ ~(1 << scb->lun);
+ aic_select(aic);
+ aic_outb(aic, DMACNTRL0, INTEN);
+ return;
+ }
+ }
+ aic->flags &= ~AIC_BUSFREE_OK;
+ aic->state = AIC_IDLE;
+ aic_start(aic);
+ aic_outb(aic, DMACNTRL0, INTEN);
+ return;
+ }
+
if ((sstat1 & REQINIT) != 0) {
u_int8_t phase = aic_inb(aic, SCSISIGI) & PH_MASK;
aic_outb(aic, SCSISIGO, phase);
@@ -1245,34 +1289,6 @@ aic_intr(void *arg)
return;
}
- if ((sstat1 & BUSFREE) != 0) {
- aic_outb(aic, SCSISEQ, 0);
- aic_outb(aic, CLRSINT0, sstat0);
- aic_outb(aic, CLRSINT1, sstat1);
- if ((scb = aic->nexus)) {
- if ((aic->flags & AIC_BUSFREE_OK) == 0) {
- ccb = scb->ccb;
- ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
- aic_done(aic, scb);
- } else if (scb->flags & SCB_DEVICE_RESET) {
- ccb = scb->ccb;
- ccb->ccb_h.status = CAM_REQ_CMP;
- aic_done(aic, scb);
- } else if (scb->flags & SCB_SENSE) {
- /* autosense request */
- aic->flags &= ~AIC_BUSFREE_OK;
- aic_select(aic);
- aic_outb(aic, DMACNTRL0, INTEN);
- return;
- }
- }
- aic->flags &= ~AIC_BUSFREE_OK;
- aic->state = AIC_IDLE;
- aic_start(aic);
- aic_outb(aic, DMACNTRL0, INTEN);
- return;
- }
-
printf("aic_intr: unexpected intr sstat0 %x sstat1 %x\n",
sstat0, sstat1);
aic_outb(aic, DMACNTRL0, INTEN);
@@ -1351,27 +1367,23 @@ aic_reset(struct aic_softc *aic, int initiate_reset)
while ((ccb_h = TAILQ_FIRST(&aic->pending_ccbs)) != NULL) {
TAILQ_REMOVE(&aic->pending_ccbs, ccb_h, sim_links.tqe);
- ccb_h->status &= ~CAM_STATUS_MASK;
ccb_h->status |= CAM_SCSI_BUS_RESET;
aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
}
while ((ccb_h = TAILQ_FIRST(&aic->nexus_ccbs)) != NULL) {
TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
- ccb_h->status &= ~CAM_STATUS_MASK;
ccb_h->status |= CAM_SCSI_BUS_RESET;
aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
}
if (aic->nexus) {
ccb_h = &aic->nexus->ccb->ccb_h;
- ccb_h->status &= ~CAM_STATUS_MASK;
ccb_h->status |= CAM_SCSI_BUS_RESET;
aic_done(aic, aic->nexus);
}
aic->state = AIC_IDLE;
-
aic_outb(aic, DMACNTRL0, INTEN);
}
diff --git a/sys/dev/aic/aic_isa.c b/sys/dev/aic/aic_isa.c
index cdf49cc..3e0c838 100644
--- a/sys/dev/aic/aic_isa.c
+++ b/sys/dev/aic/aic_isa.c
@@ -51,8 +51,8 @@ struct aic_isa_softc {
static int aic_isa_alloc_resources __P((device_t));
static void aic_isa_release_resources __P((device_t));
-static int aic_isa_probe __P((device_t dev));
-static int aic_isa_attach __P((device_t dev));
+static int aic_isa_probe __P((device_t));
+static int aic_isa_attach __P((device_t));
static u_int aic_isa_ports[] = { 0x340, 0x140 };
#define AIC_ISA_NUMPORTS (sizeof(aic_isa_ports) / sizeof(aic_isa_ports[0]))
@@ -154,6 +154,7 @@ aic_isa_probe(device_t dev)
bus_set_resource(dev, SYS_RES_IRQ, 0, PORTA_IRQ(porta), 1);
if ((aic->flags & AIC_DMA_ENABLE) && isa_get_drq(dev) == -1)
bus_set_resource(dev, SYS_RES_DRQ, 0, PORTA_DRQ(porta), 1);
+ device_set_desc(dev, "Adaptec 6260/6360 SCSI controller");
return (0);
}
diff --git a/sys/dev/aic/aicvar.h b/sys/dev/aic/aicvar.h
index 540a25a..5d789b4 100644
--- a/sys/dev/aic/aicvar.h
+++ b/sys/dev/aic/aicvar.h
@@ -106,7 +106,8 @@ struct aic_softc {
#define AIC_IDLE 0x00
#define AIC_SELECTING 0x01
#define AIC_RESELECTED 0x02
-#define AIC_HASNEXUS 0x03
+#define AIC_RECONNECTING 0x03
+#define AIC_HASNEXUS 0x04
#define AIC_MSG_IDENTIFY 0x01
#define AIC_MSG_TAG_Q 0x02
OpenPOWER on IntegriCloud