diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2000-03-01 22:38:52 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2000-03-01 22:38:52 +0000 |
commit | c440e806aa95acc4fe97664161b191c2a7e2d3ec (patch) | |
tree | 118d3ea3f7ff1102b93a5271240cdf3a105c70fe /sys/dev | |
parent | 6103bc6d00b1a47b10e50dce6983d527fc212315 (diff) |
Proper bus_dma usage, fixes cache incosistencies
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/gdt_common.c | 71 | ||||
-rw-r--r-- | sys/dev/ic/gdtvar.h | 4 | ||||
-rw-r--r-- | sys/dev/pci/gdt_pci.c | 3 |
3 files changed, 55 insertions, 23 deletions
diff --git a/sys/dev/ic/gdt_common.c b/sys/dev/ic/gdt_common.c index b18c608854d..ac5e0c33ed2 100644 --- a/sys/dev/ic/gdt_common.c +++ b/sys/dev/ic/gdt_common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdt_common.c,v 1.4 2000/02/13 11:23:15 niklas Exp $ */ +/* $OpenBSD: gdt_common.c,v 1.5 2000/03/01 22:38:51 niklas Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. @@ -107,7 +107,7 @@ gdt_attach(gdt) struct gdt_softc *gdt; { u_int16_t cdev_cnt; - int i, id, drv_cyls, drv_hds, drv_secs; + int i, id, drv_cyls, drv_hds, drv_secs, error; gdt_polling = 1; gdt_from_wait = 0; @@ -120,6 +120,16 @@ gdt_attach(gdt) /* Initialize the ccbs */ for (i = 0; i < GDT_MAXCMDS; i++) { gdt->sc_ccbs[i].gc_cmd_index = i + 2; + error = bus_dmamap_create(gdt->sc_dmat, + (GDT_MAXOFFSETS - 1) << PGSHIFT, GDT_MAXOFFSETS, + (GDT_MAXOFFSETS - 1) << PGSHIFT, 0, + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + &gdt->sc_ccbs[i].gc_dmamap_xfer); + if (error) { + printf("%s: cannot create ccb dmamap (%d)", + gdt->sc_dev.dv_xname, error); + return (1); + } (void)gdt_ccb_set_cmd(gdt->sc_ccbs + i, GDT_GCF_UNUSED); TAILQ_INSERT_TAIL(&gdt->sc_free_ccb, &gdt->sc_ccbs[i], gc_chain); @@ -460,6 +470,8 @@ gdt_scsi_cmd(xs) u_int32_t blockno, blockcnt; struct scsi_rw *rw; struct scsi_rw_big *rwb; + bus_dmamap_t xfer; + int error; GDT_DPRINTF(GDT_D_CMD, ("gdt_scsi_cmd ")); @@ -596,6 +608,26 @@ gdt_scsi_cmd(xs) ccb->gc_service = GDT_CACHESERVICE; gdt_ccb_set_cmd(ccb, GDT_GCF_SCSI); + xfer = ccb->gc_dmamap_xfer; + error = bus_dmamap_load(gdt->sc_dmat, xfer, xs->data, + xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ? + BUS_DMA_NOWAIT : BUS_DMA_WAITOK); + if (error) { + printf("%s: gdt_scsi_cmd: ", gdt->sc_dev.dv_xname); + if (error == EFBIG) + printf("more than %d dma segs\n", + GDT_MAXOFFSETS); + else + printf("error %d loading dma map\n", error); + + xs->error = XS_DRIVER_STUFFUP; + gdt_free_ccb(gdt, ccb); + return (COMPLETE); + } + bus_dmamap_sync(gdt->sc_dmat, xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + gdt_enqueue_ccb(gdt, ccb); /* XXX what if enqueue did not start a transfer? */ if (gdt_polling) { @@ -634,9 +666,8 @@ gdt_exec_ccb(ccb) struct gdt_softc *gdt = link->adapter_softc; u_int8_t target = link->target; u_int32_t sg_canz; - int i, len, off; - u_int8_t *buf; - paddr_t pa; + bus_dmamap_t xfer; + int i; GDT_DPRINTF(GDT_D_CMD, ("gdt_exec_ccb(%p, %p) ", xs, ccb)); @@ -681,34 +712,28 @@ gdt_exec_ccb(ccb) ccb->gc_blockcnt); } + xfer = ccb->gc_dmamap_xfer; if (gdt->sc_cache_feat & GDT_SCATTER_GATHER) { gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR, 0xffffffff); - len = xs->datalen; - buf = xs->data; - for (i = 0; len > 0; i++) { - for (off = PAGE_SIZE, pa = vtophys(buf); off < len; - off += PAGE_SIZE) - if (pa + off != vtophys(buf + off)) - break; - + for (i = 0; i < xfer->dm_nsegs; i++) { gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + - GDT_CACHE_SG_LST + i * GDT_SG_SZ + GDT_SG_PTR, pa); + GDT_CACHE_SG_LST + i * GDT_SG_SZ + GDT_SG_PTR, + xfer->dm_segs[i].ds_addr); gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + i * GDT_SG_SZ + GDT_SG_LEN, - MIN(off, len)); + xfer->dm_segs[i].ds_len); GDT_DPRINTF(GDT_D_IO, ("#%d va %p pa %p len %x\n", i, - buf, (void *)pa, MIN(off, len))); - - len -= off; - buf += off; + buf, xfer->dm_segs[i].ds_addr, + xfer->dm_segs[i].ds_len)); } - sg_canz = i; + sg_canz = xfer->dm_nsegs; gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + sg_canz * GDT_SG_SZ + GDT_SG_LEN, 0); } else { + /* XXX Hardly correct */ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR, - vtophys(xs->data)); + xfer->dm_segs[0].ds_addr); sg_canz = 0; } gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ, sg_canz); @@ -990,6 +1015,10 @@ gdt_intr(arg) untimeout(gdt_timeout, ccb); ctx.service = ccb->gc_service; prev_cmd = ccb->gc_flags & GDT_GCF_CMD_MASK; + bus_dmamap_sync(gdt->sc_dmat, ccb->gc_dmamap_xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(gdt->sc_dmat, ccb->gc_dmamap_xfer); gdt_free_ccb(gdt, ccb); switch (prev_cmd) { case GDT_GCF_UNUSED: diff --git a/sys/dev/ic/gdtvar.h b/sys/dev/ic/gdtvar.h index 8f3922da5cb..ee4d1cd0ce9 100644 --- a/sys/dev/ic/gdtvar.h +++ b/sys/dev/ic/gdtvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: gdtvar.h,v 1.2 2000/02/07 04:30:21 itojun Exp $ */ +/* $OpenBSD: gdtvar.h,v 1.3 2000/03/01 22:38:51 niklas Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. @@ -68,6 +68,7 @@ struct gdt_intr_ctx { struct gdt_ccb { TAILQ_ENTRY(gdt_ccb) gc_chain; struct scsi_xfer *gc_xs; + bus_dmamap_t gc_dmamap_xfer; int gc_timeout; u_int32_t gc_info; u_int32_t gc_blockno; @@ -116,6 +117,7 @@ struct gdt_softc { bus_space_tag_t sc_dpmemt; bus_space_handle_t sc_dpmemh; bus_addr_t sc_dpmembase; + bus_dma_tag_t sc_dmat; /* XXX These could go into a class-dependent opaque struct instead */ bus_space_tag_t sc_iot; diff --git a/sys/dev/pci/gdt_pci.c b/sys/dev/pci/gdt_pci.c index a2fdf58b851..22f80c96763 100644 --- a/sys/dev/pci/gdt_pci.c +++ b/sys/dev/pci/gdt_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdt_pci.c,v 1.2 2000/02/13 10:59:06 niklas Exp $ */ +/* $OpenBSD: gdt_pci.c,v 1.3 2000/03/01 22:38:51 niklas Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. @@ -286,6 +286,7 @@ gdt_pci_attach(parent, self, aux) gdt->sc_dpmemt = dpmemt; gdt->sc_dpmemh = dpmemh; gdt->sc_dpmembase = dpmembase; + gdt->sc_dmat = pa->pa_dmat; /* * The GDT_PCINEW series also has two other regions to map. |