summaryrefslogtreecommitdiffstats
path: root/sys/dev/amr
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-07-17 19:45:47 +0000
committerjhb <jhb@FreeBSD.org>2006-07-17 19:45:47 +0000
commitcd6451f0ca0576c0a75a95651c7c8d37e33bebf3 (patch)
treec5ee286f667cc5abbe0d1c2555b08e5da7c4740c /sys/dev/amr
parent431401cbc0bdc513f5446f700c4a4e28ed919042 (diff)
downloadFreeBSD-src-cd6451f0ca0576c0a75a95651c7c8d37e33bebf3.zip
FreeBSD-src-cd6451f0ca0576c0a75a95651c7c8d37e33bebf3.tar.gz
Chain the bus_dmamap_load() calls when mapping a command with a data CCB
instead of doing the first load with the BUS_DMA_NOWAIT flag. On 4.x with PAE and > 4gb of RAM this proved disastrous if there weren't enough bounce pages as amr_mapcmd() would return failure but the callback would later fire once enough bounce pages were available and would then overwrite another command's S/G list. MFC after: 3 days Submitted by: scottl (4.x version) Reviewed by: scottl (port from 4.x to HEAD)
Diffstat (limited to 'sys/dev/amr')
-rw-r--r--sys/dev/amr/amr.c66
1 files changed, 42 insertions, 24 deletions
diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c
index 561567d..52db8fb 100644
--- a/sys/dev/amr/amr.c
+++ b/sys/dev/amr/amr.c
@@ -1785,13 +1785,44 @@ amr_setup_ccb64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
}
}
+static void
+amr_setup_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegments,
+ int error)
+{
+ struct amr_command *ac = (struct amr_command *)arg;
+ struct amr_softc *sc = ac->ac_sc;
+
+ amr_setup_dmamap(arg, segs, nsegments, error);
+
+ if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
+ ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac,
+ 0) == EINPROGRESS) {
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
+ }
+}
+
+static void
+amr_setup_dma64map_cb(void *arg, bus_dma_segment_t *segs, int nsegments,
+ int error)
+{
+ struct amr_command *ac = (struct amr_command *)arg;
+ struct amr_softc *sc = ac->ac_sc;
+
+ amr_setup_dma64map(arg, segs, nsegments, error);
+
+ if (bus_dmamap_load(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map,
+ ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccb64map, ac,
+ 0) == EINPROGRESS) {
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
+ }
+}
+
static int
amr_mapcmd(struct amr_command *ac)
{
bus_dma_tag_t tag;
- bus_dmamap_t datamap, ccbmap;
+ bus_dmamap_t datamap;
bus_dmamap_callback_t *cb;
- bus_dmamap_callback_t *ccb_cb;
struct amr_softc *sc = ac->ac_sc;
debug_called(3);
@@ -1799,35 +1830,22 @@ amr_mapcmd(struct amr_command *ac)
if (AC_IS_SG64(ac)) {
tag = sc->amr_buffer64_dmat;
datamap = ac->ac_dma64map;
- ccbmap = ac->ac_ccb_dma64map;
- cb = amr_setup_dma64map;
- ccb_cb = amr_setup_ccb64map;
+ cb = amr_setup_dma64map_cb;
} else {
tag = sc->amr_buffer_dmat;
datamap = ac->ac_dmamap;
- ccbmap = ac->ac_ccb_dmamap;
- cb = amr_setup_dmamap;
- ccb_cb = amr_setup_ccbmap;
+ cb = amr_setup_dmamap_cb;
}
/* if the command involves data at all, and hasn't been mapped */
if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) {
- if (ac->ac_ccb_data == NULL) {
- /* map the data buffers into bus space and build the s/g list */
- if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
- amr_setup_data_dmamap, ac, 0) == EINPROGRESS) {
- sc->amr_state |= AMR_STATE_QUEUE_FRZN;
- }
- } else {
- if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
- cb, ac, BUS_DMA_NOWAIT) != 0) {
- return (ENOMEM);
- }
- if (bus_dmamap_load(tag, ccbmap, ac->ac_ccb_data,
- ac->ac_ccb_length, ccb_cb, ac, 0) == EINPROGRESS) {
- sc->amr_state |= AMR_STATE_QUEUE_FRZN;
- }
- }
+ if (ac->ac_ccb_data == NULL)
+ cb = amr_setup_data_dmamap;
+ /* map the data buffers into bus space and build the s/g list */
+ if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
+ cb, ac, 0) == EINPROGRESS) {
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
+ }
} else {
if (sc->amr_submit_command(ac) == EBUSY) {
amr_freeslot(ac);
OpenPOWER on IntegriCloud