summaryrefslogtreecommitdiffstats
path: root/sys/dev/twe
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2005-02-08 03:43:02 +0000
committerscottl <scottl@FreeBSD.org>2005-02-08 03:43:02 +0000
commit29a3025dfa67b87f11e6cf880de2420340df3455 (patch)
tree1fb306fb5eae3d7a82f002359b9883dd51213c5b /sys/dev/twe
parentc9612f2230ffb12397831f67ffc348af859259d1 (diff)
downloadFreeBSD-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/dev/twe')
-rw-r--r--sys/dev/twe/twe.c33
-rw-r--r--sys/dev/twe/twe_freebsd.c4
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);
OpenPOWER on IntegriCloud