summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorChristopher Pascoe <pascoe@cvs.openbsd.org>2007-04-07 09:24:13 +0000
committerChristopher Pascoe <pascoe@cvs.openbsd.org>2007-04-07 09:24:13 +0000
commit6942f399874bc8679cf7650aa905cdfcb417e064 (patch)
treedf578cb9fff8d887db1aabd5cf7ccf08c25f59d3 /sys/dev/ic
parent41ac00b94011657d6eac963f64532477a117c296 (diff)
Add infrastructure to handle more than one ccb.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/sili.c118
1 files changed, 90 insertions, 28 deletions
diff --git a/sys/dev/ic/sili.c b/sys/dev/ic/sili.c
index 6a05090ac19..dd20133fc99 100644
--- a/sys/dev/ic/sili.c
+++ b/sys/dev/ic/sili.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sili.c,v 1.15 2007/04/07 06:10:09 dlg Exp $ */
+/* $OpenBSD: sili.c,v 1.16 2007/04/07 09:24:12 pascoe Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -72,6 +72,8 @@ struct sili_port {
struct sili_ccb *sp_ccbs;
struct sili_dmamem *sp_cmds;
+
+ TAILQ_HEAD(, sili_ccb) sp_free_ccbs;
};
int sili_ports_alloc(struct sili_softc *);
@@ -102,10 +104,14 @@ struct sili_ccb {
bus_dmamap_t ccb_dmamap;
struct sili_port *ccb_port;
+
+ TAILQ_ENTRY(sili_ccb) ccb_entry;
};
int sili_ccb_alloc(struct sili_port *);
void sili_ccb_free(struct sili_port *);
+struct sili_ccb *sili_get_ccb(struct sili_port *);
+void sili_put_ccb(struct sili_ccb *);
/* bus space ops */
u_int32_t sili_read(struct sili_softc *, bus_size_t);
@@ -159,7 +165,7 @@ sili_attach(struct sili_softc *sc)
aaa.aaa_methods = &sili_atascsi_methods;
aaa.aaa_minphys = minphys;
aaa.aaa_nports = sc->sc_nports;
- aaa.aaa_ncmds = 1 /* XXX SILI_MAX_CMDS */;
+ aaa.aaa_ncmds = SILI_MAX_CMDS;
sc->sc_atascsi = atascsi_attach(&sc->sc_dev, &aaa);
@@ -236,31 +242,46 @@ sili_ccb_alloc(struct sili_port *sp)
{
struct sili_softc *sc = sp->sp_sc;
struct sili_ccb *ccb;
+ struct sili_prb *prb;
+ int i;
- /* XXX this should allocate multiple ccbs */
+ TAILQ_INIT(&sp->sp_free_ccbs);
- sp->sp_ccbs = malloc(sizeof(struct sili_ccb), M_DEVBUF, M_WAITOK);
- sp->sp_cmds = sili_dmamem_alloc(sc, SILI_CMD_LEN /* * SILI_MAX_CMDS */,
+ sp->sp_ccbs = malloc(sizeof(struct sili_ccb) * SILI_MAX_CMDS,
+ M_DEVBUF, M_WAITOK);
+ sp->sp_cmds = sili_dmamem_alloc(sc, SILI_CMD_LEN * SILI_MAX_CMDS,
SILI_PRB_ALIGN);
if (sp->sp_cmds == NULL)
goto free_ccbs;
- ccb = sp->sp_ccbs;
- bzero(ccb, sizeof(struct sili_ccb));
- ccb->ccb_port = sp;
- ccb->ccb_cmd = SILI_DMA_KVA(sp->sp_cmds);
- ccb->ccb_cmd_dva = SILI_DMA_DVA(sp->sp_cmds);
- if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, SILI_DMA_SEGS,
- MAXPHYS, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
- &sp->sp_ccbs->ccb_dmamap) != 0)
- goto free_cmds;
+ bzero(sp->sp_ccbs, sizeof(struct sili_ccb) * SILI_MAX_CMDS);
+
+ for (i = 0; i < SILI_MAX_CMDS; i++) {
+ ccb = &sp->sp_ccbs[i];
+ ccb->ccb_port = sp;
+ ccb->ccb_cmd = SILI_DMA_KVA(sp->sp_cmds) + i * SILI_CMD_LEN;
+ ccb->ccb_cmd_dva = SILI_DMA_DVA(sp->sp_cmds) + i * SILI_CMD_LEN;
+ if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, SILI_DMA_SEGS,
+ MAXPHYS, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
+ &ccb->ccb_dmamap) != 0)
+ goto free_cmds;
+
+ prb = ccb->ccb_cmd;
+ ccb->ccb_xa.fis = (struct ata_fis_h2d *)&prb->fis;
+ ccb->ccb_xa.packetcmd = ((struct sili_prb_packet *)prb)->cdb;
+ ccb->ccb_xa.tag = i;
+ ccb->ccb_xa.ata_put_xfer = sili_ata_put_xfer;
+ ccb->ccb_xa.state = ATA_S_COMPLETE;
+
+ sili_put_ccb(ccb);
+ }
return (0);
free_cmds:
sili_dmamem_free(sc, sp->sp_cmds);
free_ccbs:
- free(sp->sp_ccbs, M_DEVBUF);
+ sili_ccb_free(sp);
return (1);
}
@@ -270,13 +291,47 @@ sili_ccb_free(struct sili_port *sp)
struct sili_softc *sc = sp->sp_sc;
struct sili_ccb *ccb;
- ccb = sp->sp_ccbs;
- bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
+ while ((ccb = sili_get_ccb(sp)) != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
free(sp->sp_ccbs, M_DEVBUF);
sp->sp_ccbs = NULL;
}
+struct sili_ccb *
+sili_get_ccb(struct sili_port *sp)
+{
+ struct sili_ccb *ccb;
+
+ ccb = TAILQ_FIRST(&sp->sp_free_ccbs);
+ if (ccb != NULL) {
+ KASSERT(ccb->ccb_xa.state == ATA_S_PUT);
+ TAILQ_REMOVE(&sp->sp_free_ccbs, ccb, ccb_entry);
+ ccb->ccb_xa.state = ATA_S_SETUP;
+ }
+
+ return (ccb);
+}
+
+void
+sili_put_ccb(struct sili_ccb *ccb)
+{
+ struct sili_port *sp = ccb->ccb_port;
+
+#ifdef DIAGNOSTIC
+ if (ccb->ccb_xa.state != ATA_S_COMPLETE &&
+ ccb->ccb_xa.state != ATA_S_TIMEOUT &&
+ ccb->ccb_xa.state != ATA_S_ERROR) {
+ printf("%s: invalid ata_xfer state %02x in sili_put_ccb, "
+ "slot %d\n", DEVNAME(sp->sp_sc), ccb->ccb_xa.state,
+ ccb->ccb_xa.tag);
+ }
+#endif
+
+ ccb->ccb_xa.state = ATA_S_PUT;
+ TAILQ_INSERT_TAIL(&sp->sp_free_ccbs, ccb, ccb_entry);
+}
+
struct sili_dmamem *
sili_dmamem_alloc(struct sili_softc *sc, bus_size_t size, bus_size_t align)
{
@@ -512,6 +567,7 @@ sili_ata_cmd(struct ata_xfer *xa)
sgl = atapi->sgl;
sgllen = sizeofa(atapi->sgl);
+ xa->state = ATA_S_ERROR;
return (ATA_ERROR);
} else {
ata = ccb->ccb_cmd;
@@ -522,8 +578,10 @@ sili_ata_cmd(struct ata_xfer *xa)
sgllen = sizeofa(ata->sgl);
}
- if (sili_load(ccb, sgl, sgllen) != 0)
+ if (sili_load(ccb, sgl, sgllen) != 0) {
+ xa->state = ATA_S_ERROR;
return (ATA_ERROR);
+ }
bus_dmamap_sync(sc->sc_dmat, SILI_DMA_MAP(sp->sp_cmds),
0, SILI_CMD_LEN, BUS_DMASYNC_PREWRITE);
@@ -531,8 +589,10 @@ sili_ata_cmd(struct ata_xfer *xa)
sili_post_direct(sp, 0, &ccb->ccb_prb, sizeof(ccb->ccb_prb));
#endif
sili_post_indirect(sp, ccb);
- if (!sili_pwait_eq(sp, SILI_PREG_PSS, (1 << 0), 0, 1000)) {
+ if (!sili_pwait_eq(sp, SILI_PREG_PSS, (1 << ccb->ccb_xa.tag), 0,
+ ccb->ccb_xa.timeout)) {
printf("%s: cmd failed\n", DEVNAME(sp->sp_sc));
+ xa->state = ATA_S_ERROR;
return (ATA_ERROR);
}
@@ -635,21 +695,23 @@ sili_ata_get_xfer(void *xsc, int port)
{
struct sili_softc *sc = xsc;
struct sili_port *sp = &sc->sc_ports[port];
- struct sili_ccb *ccb = sp->sp_ccbs;
- struct sili_prb *prb = ccb->ccb_cmd;
- struct ata_xfer *xa;
+ struct sili_ccb *ccb;
- bzero(ccb->ccb_cmd, SILI_CMD_LEN);
+ ccb = sili_get_ccb(sp);
+ if (ccb == NULL) {
+ printf("sili_ata_get_xfer: NULL ccb\n");
+ return (NULL);
+ }
- xa = &ccb->ccb_xa;
- xa->fis = (struct ata_fis_h2d *)&prb->fis;
- xa->ata_put_xfer = sili_ata_put_xfer;
+ bzero(ccb->ccb_cmd, SILI_CMD_LEN);
- return (xa);
+ return ((struct ata_xfer *)ccb);
}
void
sili_ata_put_xfer(struct ata_xfer *xa)
{
- /* this does nothing (yet) */
+ struct sili_ccb *ccb = (struct sili_ccb *)xa;
+
+ sili_put_ccb(ccb);
}