diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c index 787c49b708d1..e3c20738a97a 100644 --- a/sys/dev/twe/twe.c +++ b/sys/dev/twe/twe.c @@ -431,16 +431,19 @@ twe_startio(struct twe_softc *sc) if (tr == NULL) break; - /* map the command so the controller can work with it */ + /* try to map and submit the command to controller */ error = twe_map_request(tr); - if (error != 0) { - if (error == EBUSY) { - twe_requeue_ready(tr); /* try it again later */ - break; /* don't try anything more for now */ - } - /* we don't support any other return from twe_start */ - twe_panic(sc, "twe_map_request returned nonsense"); + if (error != 0) { + tr->tr_status = TWE_CMD_ERROR; + if (tr->tr_private != NULL) { + bp = (twe_bio *)(tr->tr_private); + TWE_BIO_SET_ERROR(bp, error); + tr->tr_private = NULL; + twed_intr(bp); + twe_release_request(tr); + } else if (tr->tr_flags & TWE_CMD_SLEEPER) + wakeup_one(tr); /* wakeup the sleeping owner */ } } } @@ -529,7 +532,9 @@ twe_ioctl(struct twe_softc *sc, int ioctlcmd, void *addr) } /* run the command */ - twe_wait_request(tr); + error = twe_wait_request(tr); + if (error) + goto cmd_done; /* copy the command out again */ bcopy(cmd, &tu->tu_command, sizeof(TWE_Command)); @@ -880,8 +885,6 @@ twe_init_connection(struct twe_softc *sc, int mode) /* submit the command */ error = twe_immediate_request(tr); - /* XXX check command result? */ - twe_unmap_request(tr); twe_release_request(tr); if (mode == TWE_INIT_MESSAGE_CREDITS) @@ -910,7 +913,7 @@ twe_wait_request(struct twe_request *tr) tsleep(tr, PRIBIO, "twewait", 0); splx(s); - return(0); + return(tr->tr_status != TWE_CMD_COMPLETE); } /******************************************************************************** @@ -921,13 +924,14 @@ twe_wait_request(struct twe_request *tr) static int twe_immediate_request(struct twe_request *tr) { + int error; debug_called(4); tr->tr_flags |= TWE_CMD_IMMEDIATE; tr->tr_status = TWE_CMD_BUSY; - twe_map_request(tr); - + if ((error = twe_map_request(tr)) != 0) + return(error); while (tr->tr_status == TWE_CMD_BUSY){ twe_done(tr->tr_sc); } @@ -1174,8 +1178,6 @@ twe_complete(struct twe_softc *sc) debug(2, "command left for owner"); } } - - sc->twe_state &= ~TWE_STATE_FRZN; } /******************************************************************************** @@ -1842,7 +1844,7 @@ twe_panic(struct twe_softc *sc, char *reason) #endif } -#ifdef TWE_DEBUG +#if 0 /******************************************************************************** * Print a request/command in human-readable format. */ diff --git a/sys/dev/twe/twe_freebsd.c b/sys/dev/twe/twe_freebsd.c index 6b5cf4bd0ebf..0f04532b845b 100644 --- a/sys/dev/twe/twe_freebsd.c +++ b/sys/dev/twe/twe_freebsd.c @@ -939,6 +939,8 @@ twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int err tr->tr_flags |= TWE_CMD_MAPPED; + if (tr->tr_flags & TWE_CMD_IN_PROGRESS) + sc->twe_state &= ~TWE_STATE_FRZN; /* save base of first segment in command (applicable if there only one segment) */ tr->tr_dataphys = segs[0].ds_addr; @@ -1051,26 +1053,35 @@ twe_map_request(struct twe_request *tr) if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) { tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */ tr->tr_flags |= TWE_CMD_ALIGNBUF; - tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT); /* XXX check result here */ + tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT); + if (tr->tr_data == NULL) { + twe_printf(sc, "%s: malloc failed\n", __func__); + tr->tr_data = tr->tr_realdata; /* restore original data pointer */ + return(ENOMEM); + } } /* * 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); - bus_dmamap_load(sc->twe_immediate_dmat, sc->twe_immediate_map, sc->twe_immediate, + error = bus_dmamap_load(sc->twe_immediate_dmat, sc->twe_immediate_map, sc->twe_immediate, tr->tr_length, twe_setup_data_dmamap, tr, 0); } else { error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, twe_setup_data_dmamap, tr, 0); } if (error == EINPROGRESS) { + tr->tr_flags |= TWE_CMD_IN_PROGRESS; sc->twe_state |= TWE_STATE_FRZN; error = 0; } } else - error = twe_start(tr); + if ((error = twe_start(tr)) == EBUSY) { + twe_requeue_ready(tr); + error = 0; + } return(error); } @@ -1127,6 +1138,7 @@ twe_unmap_request(struct twe_request *tr) } #ifdef TWE_DEBUG +void twe_report(void); /******************************************************************************** * Print current controller status, call from DDB. */ diff --git a/sys/dev/twe/twevar.h b/sys/dev/twe/twevar.h index e39c88e7d75c..9b8aa7a972b4 100644 --- a/sys/dev/twe/twevar.h +++ b/sys/dev/twe/twevar.h @@ -31,7 +31,7 @@ * The scheme for the driver version is: * ..<3ware internal release>. */ -#define TWE_DRIVER_VERSION_STRING "1.50.00.000" +#define TWE_DRIVER_VERSION_STRING "1.50.01.000" #ifdef TWE_DEBUG #define debug(level, fmt, args...) \ @@ -89,6 +89,7 @@ struct twe_request #define TWE_CMD_SETUP 0 /* being assembled */ #define TWE_CMD_BUSY 1 /* submitted to controller */ #define TWE_CMD_COMPLETE 2 /* completed by controller (maybe with error) */ +#define TWE_CMD_ERROR 3 /* encountered error, even before submission to controller */ int tr_flags; #define TWE_CMD_DATAIN (1<<0) #define TWE_CMD_DATAOUT (1<<1) @@ -96,6 +97,7 @@ struct twe_request #define TWE_CMD_SLEEPER (1<<3) /* owner is sleeping on this command */ #define TWE_CMD_IMMEDIATE (1<<4) /* immediate request */ #define TWE_CMD_MAPPED (1<<5) +#define TWE_CMD_IN_PROGRESS (1<<6) /* bus_dmamap_load returned EINPROGRESS */ void (* tr_complete)(struct twe_request *tr); /* completion handler */ void *tr_private; /* submitter-private data or wait channel */