diff options
author | scottl <scottl@FreeBSD.org> | 2005-02-08 03:43:02 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2005-02-08 03:43:02 +0000 |
commit | 29a3025dfa67b87f11e6cf880de2420340df3455 (patch) | |
tree | 1fb306fb5eae3d7a82f002359b9883dd51213c5b /sys | |
parent | c9612f2230ffb12397831f67ffc348af859259d1 (diff) | |
download | FreeBSD-src-29a3025dfa67b87f11e6cf880de2420340df3455.zip FreeBSD-src-29a3025dfa67b87f11e6cf880de2420340df3455.tar.gz |
Fix crashdumps on twe. The twe_immediate_request() path was not only
copying data to a temporary buffer before the I/O, but also copying that
temporary buffer back to the original data location after the I/O. When
you're dumping kernel heap and stack and protected pages, this is very
very bad.
A belated thanks to Robert Watson for donating hardware for this (and future)
work.
MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/twe/twe.c | 33 | ||||
-rw-r--r-- | sys/dev/twe/twe_freebsd.c | 4 |
2 files changed, 25 insertions, 12 deletions
diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c index 6ee9db5..3ecd19d 100644 --- a/sys/dev/twe/twe.c +++ b/sys/dev/twe/twe.c @@ -59,7 +59,7 @@ static int twe_set_param(struct twe_softc *sc, int table_id, int param_id, int p void *data); static int twe_init_connection(struct twe_softc *sc, int mode); static int twe_wait_request(struct twe_request *tr); -static int twe_immediate_request(struct twe_request *tr); +static int twe_immediate_request(struct twe_request *tr, int usetmp); static void twe_completeio(struct twe_request *tr); static void twe_reset(struct twe_softc *sc); static int twe_add_unit(struct twe_softc *sc, int unit); @@ -475,7 +475,7 @@ twe_dump_blocks(struct twe_softc *sc, int unit, u_int32_t lba, void *data, int n cmd->io.block_count = nblks; cmd->io.lba = lba; - error = twe_immediate_request(tr); + error = twe_immediate_request(tr, 0); if (error == 0) if (twe_report_request(tr)) error = EIO; @@ -788,7 +788,7 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz /* submit the command and either wait or let the callback handle it */ if (func == NULL) { /* XXX could use twe_wait_request here if interrupts were enabled? */ - error = twe_immediate_request(tr); + error = twe_immediate_request(tr, 1 /* usetmp */); if (error == 0) { if (twe_report_request(tr)) goto err; @@ -881,7 +881,7 @@ twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, bcopy(data, param->data, param_size); /* XXX could use twe_wait_request here if interrupts were enabled? */ - error = twe_immediate_request(tr); + error = twe_immediate_request(tr, 1 /* usetmp */); if (error == 0) { if (twe_report_request(tr)) error = EIO; @@ -922,7 +922,7 @@ twe_init_connection(struct twe_softc *sc, int mode) cmd->initconnection.response_queue_pointer = 0; /* submit the command */ - error = twe_immediate_request(tr); + error = twe_immediate_request(tr, 0 /* usetmp */); twe_release_request(tr); if (mode == TWE_INIT_MESSAGE_CREDITS) @@ -960,20 +960,35 @@ twe_wait_request(struct twe_request *tr) * will work if they are not). */ static int -twe_immediate_request(struct twe_request *tr) +twe_immediate_request(struct twe_request *tr, int usetmp) { + struct twe_softc *sc; int error; + int count = 0; debug_called(4); - tr->tr_flags |= TWE_CMD_IMMEDIATE; + sc = tr->tr_sc; + + if (usetmp && (tr->tr_data != NULL)) { + tr->tr_flags |= TWE_CMD_IMMEDIATE; + if (tr->tr_length > MAXBSIZE) + return (EINVAL); + bcopy(tr->tr_data, sc->twe_immediate, tr->tr_length); + } tr->tr_status = TWE_CMD_BUSY; if ((error = twe_map_request(tr)) != 0) if (error != EBUSY) return(error); - while (tr->tr_status == TWE_CMD_BUSY){ - twe_done(tr->tr_sc); + + /* Wait up to 5 seconds for the command to complete */ + while ((count++ < 5000) && (tr->tr_status == TWE_CMD_BUSY)){ + DELAY(1000); + twe_done(sc); } + if (usetmp && (tr->tr_data != NULL)) + bcopy(sc->twe_immediate, tr->tr_data, tr->tr_length); + return(tr->tr_status != TWE_CMD_COMPLETE); } diff --git a/sys/dev/twe/twe_freebsd.c b/sys/dev/twe/twe_freebsd.c index a29b3dd..fd0a993 100644 --- a/sys/dev/twe/twe_freebsd.c +++ b/sys/dev/twe/twe_freebsd.c @@ -1069,9 +1069,8 @@ twe_map_request(struct twe_request *tr) * Map the data buffer into bus space and build the s/g list. */ if (tr->tr_flags & TWE_CMD_IMMEDIATE) { - bcopy(tr->tr_data, sc->twe_immediate, tr->tr_length); error = bus_dmamap_load(sc->twe_immediate_dmat, sc->twe_immediate_map, sc->twe_immediate, - tr->tr_length, twe_setup_data_dmamap, tr, 0); + tr->tr_length, twe_setup_data_dmamap, tr, BUS_DMA_NOWAIT); } else { error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, twe_setup_data_dmamap, tr, 0); @@ -1127,7 +1126,6 @@ twe_unmap_request(struct twe_request *tr) } if (tr->tr_flags & TWE_CMD_IMMEDIATE) { - bcopy(sc->twe_immediate, tr->tr_data, tr->tr_length); bus_dmamap_unload(sc->twe_immediate_dmat, sc->twe_immediate_map); } else { bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap); |