- add support for crashdumps (courtesy of ps and Y!)
- standardise error reporting for commands - simplify the driver-to-controller bio transfer - add bio in/out accounting - correctly preserve the command ID in twe_ioctl (thanks to joel@3ware)
This commit is contained in:
parent
5870e2e9f0
commit
0767ccf15b
@ -54,7 +54,6 @@ static int twe_set_param(struct twe_softc *sc, int table_id, int param_id, int p
|
||||
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 void twe_startio(struct twe_softc *sc);
|
||||
static void twe_completeio(struct twe_request *tr);
|
||||
static void twe_reset(struct twe_softc *sc);
|
||||
|
||||
@ -96,6 +95,7 @@ static void twe_release_request(struct twe_request *tr);
|
||||
* Debugging.
|
||||
*/
|
||||
static char *twe_format_aen(struct twe_softc *sc, u_int16_t aen);
|
||||
static int twe_report_request(struct twe_request *tr);
|
||||
static int twe_request_qlen(struct twe_request *tr);
|
||||
static void twe_panic(struct twe_softc *sc, char *reason);
|
||||
|
||||
@ -320,20 +320,113 @@ twe_intr(struct twe_softc *sc)
|
||||
twe_done(sc);
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Receive a bio structure from a child device and queue it on a particular
|
||||
* controller, then poke the controller to start as much work as it can.
|
||||
/********************************************************************************
|
||||
* Pull as much work off the softc's work queue as possible and give it to the
|
||||
* controller.
|
||||
*/
|
||||
int
|
||||
twe_submit_bio(struct twe_softc *sc, twe_bio *bp)
|
||||
void
|
||||
twe_startio(struct twe_softc *sc)
|
||||
{
|
||||
|
||||
struct twe_request *tr;
|
||||
TWE_Command *cmd;
|
||||
twe_bio *bp;
|
||||
int error;
|
||||
|
||||
debug_called(4);
|
||||
|
||||
twe_enqueue_bio(sc, bp);
|
||||
/* spin until something prevents us from doing any work */
|
||||
for (;;) {
|
||||
|
||||
twe_startio(sc);
|
||||
return(0);
|
||||
/* try to get a command that's already ready to go */
|
||||
tr = twe_dequeue_ready(sc);
|
||||
|
||||
/* build a command from an outstanding bio */
|
||||
if (tr == NULL) {
|
||||
|
||||
/* see if there's work to be done */
|
||||
if ((bp = twe_dequeue_bio(sc)) == NULL)
|
||||
break;
|
||||
|
||||
/* get a command to handle the bio with */
|
||||
if (twe_get_request(sc, &tr)) {
|
||||
twe_enqueue_bio(sc, bp); /* failed, put the bio back */
|
||||
break;
|
||||
}
|
||||
|
||||
/* connect the bio to the command */
|
||||
tr->tr_complete = twe_completeio;
|
||||
tr->tr_private = bp;
|
||||
tr->tr_data = TWE_BIO_DATA(bp);
|
||||
tr->tr_length = TWE_BIO_LENGTH(bp);
|
||||
cmd = &tr->tr_command;
|
||||
if (TWE_BIO_IS_READ(bp)) {
|
||||
tr->tr_flags |= TWE_CMD_DATAIN;
|
||||
cmd->io.opcode = TWE_OP_READ;
|
||||
} else {
|
||||
tr->tr_flags |= TWE_CMD_DATAOUT;
|
||||
cmd->io.opcode = TWE_OP_WRITE;
|
||||
}
|
||||
|
||||
/* build a suitable I/O command (assumes 512-byte rounded transfers) */
|
||||
cmd->io.size = 3;
|
||||
cmd->io.unit = TWE_BIO_UNIT(bp);
|
||||
cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE;
|
||||
cmd->io.lba = TWE_BIO_LBA(bp);
|
||||
|
||||
/* map the command so the controller can work with it */
|
||||
twe_map_request(tr);
|
||||
}
|
||||
|
||||
/* did we find something to do? */
|
||||
if (tr == NULL)
|
||||
break;
|
||||
|
||||
/* try to give command to controller */
|
||||
error = twe_start(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_start returned nonsense");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Write blocks from memory to disk, for system crash dumps.
|
||||
*/
|
||||
int
|
||||
twe_dump_blocks(struct twe_softc *sc, int unit, u_int32_t lba, void *data, int nblks)
|
||||
{
|
||||
struct twe_request *tr;
|
||||
TWE_Command *cmd;
|
||||
int error;
|
||||
|
||||
if (twe_get_request(sc, &tr))
|
||||
return(ENOMEM);
|
||||
|
||||
tr->tr_data = data;
|
||||
tr->tr_status = TWE_CMD_SETUP;
|
||||
tr->tr_length = nblks * TWE_BLOCK_SIZE;
|
||||
tr->tr_flags = TWE_CMD_DATAOUT;
|
||||
|
||||
cmd = &tr->tr_command;
|
||||
cmd->io.opcode = TWE_OP_WRITE;
|
||||
cmd->io.size = 3;
|
||||
cmd->io.unit = unit;
|
||||
cmd->io.block_count = nblks;
|
||||
cmd->io.lba = lba;
|
||||
|
||||
twe_map_request(tr);
|
||||
error = twe_immediate_request(tr);
|
||||
if (error == 0)
|
||||
if (twe_report_request(tr))
|
||||
error = EIO;
|
||||
twe_release_request(tr);
|
||||
return(error);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -349,6 +442,7 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
|
||||
void *data;
|
||||
int *arg = (int *)addr;
|
||||
struct twe_request *tr;
|
||||
u_int8_t srid;
|
||||
int s, error;
|
||||
|
||||
error = 0;
|
||||
@ -361,8 +455,13 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
|
||||
goto cmd_done;
|
||||
}
|
||||
|
||||
/* copy the user-supplied command */
|
||||
/*
|
||||
* Save the command's request ID, copy the user-supplied command in,
|
||||
* restore the request ID.
|
||||
*/
|
||||
srid = tr->tr_command.generic.request_id;
|
||||
bcopy(&tu->tu_command, &tr->tr_command, sizeof(TWE_Command));
|
||||
tr->tr_command.generic.request_id = srid;
|
||||
|
||||
/* if there's a data buffer, allocate and copy it in */
|
||||
tr->tr_length = tu->tu_size;
|
||||
@ -377,6 +476,7 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
|
||||
}
|
||||
|
||||
/* run the command */
|
||||
twe_map_request(tr);
|
||||
twe_wait_request(tr);
|
||||
|
||||
/* copy the command out again */
|
||||
@ -590,21 +690,8 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz
|
||||
/* XXX could use twe_wait_request here if interrupts were enabled? */
|
||||
error = twe_immediate_request(tr);
|
||||
if (error == 0) {
|
||||
switch (cmd->generic.flags) {
|
||||
case TWE_FLAGS_SUCCESS:
|
||||
break;
|
||||
case TWE_FLAGS_INFORMATIONAL:
|
||||
case TWE_FLAGS_WARNING:
|
||||
twe_printf(sc, "command completed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
break;
|
||||
|
||||
case TWE_FLAGS_FATAL:
|
||||
default:
|
||||
twe_printf(sc, "command failed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
if (twe_report_request(tr))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
twe_release_request(tr);
|
||||
return(param);
|
||||
@ -693,22 +780,8 @@ twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size,
|
||||
/* XXX could use twe_wait_request here if interrupts were enabled? */
|
||||
error = twe_immediate_request(tr);
|
||||
if (error == 0) {
|
||||
switch (cmd->generic.flags) {
|
||||
case TWE_FLAGS_SUCCESS:
|
||||
break;
|
||||
case TWE_FLAGS_INFORMATIONAL:
|
||||
case TWE_FLAGS_WARNING:
|
||||
twe_printf(sc, "command completed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
break;
|
||||
|
||||
case TWE_FLAGS_FATAL:
|
||||
default:
|
||||
twe_printf(sc, "command failed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
if (twe_report_request(tr))
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@ -805,87 +878,12 @@ twe_immediate_request(struct twe_request *tr)
|
||||
return(tr->tr_status != TWE_CMD_COMPLETE);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Pull as much work off the softc's work queue as possible and give it to the
|
||||
* controller.
|
||||
*/
|
||||
static void
|
||||
twe_startio(struct twe_softc *sc)
|
||||
{
|
||||
struct twe_request *tr;
|
||||
TWE_Command *cmd;
|
||||
twe_bio *bp;
|
||||
int error;
|
||||
|
||||
debug_called(4);
|
||||
|
||||
/* spin until something prevents us from doing any work */
|
||||
for (;;) {
|
||||
|
||||
/* try to get a command that's already ready to go */
|
||||
tr = twe_dequeue_ready(sc);
|
||||
|
||||
/* build a command from an outstanding bio */
|
||||
if (tr == NULL) {
|
||||
/* see if there's work to be done */
|
||||
if ((bp = twe_dequeue_bio(sc)) == NULL)
|
||||
break;
|
||||
/* get a command */
|
||||
if (twe_get_request(sc, &tr)) {
|
||||
twe_enqueue_bio(sc, bp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* connect the bio to the command */
|
||||
tr->tr_complete = twe_completeio;
|
||||
tr->tr_private = bp;
|
||||
tr->tr_data = TWE_BIO_DATA(bp);
|
||||
tr->tr_length = TWE_BIO_LENGTH(bp);
|
||||
cmd = &tr->tr_command;
|
||||
if (TWE_BIO_IS_READ(bp)) {
|
||||
tr->tr_flags |= TWE_CMD_DATAIN;
|
||||
cmd->io.opcode = TWE_OP_READ;
|
||||
} else {
|
||||
tr->tr_flags |= TWE_CMD_DATAOUT;
|
||||
cmd->io.opcode = TWE_OP_WRITE;
|
||||
}
|
||||
|
||||
/* build a suitable I/O command (assumes 512-byte rounded transfers) */
|
||||
cmd->io.size = 3;
|
||||
cmd->io.unit = TWE_BIO_UNIT(bp);
|
||||
cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE;
|
||||
cmd->io.lba = TWE_BIO_LBA(bp);
|
||||
|
||||
/* map the command so the controller can work with it */
|
||||
twe_map_request(tr);
|
||||
}
|
||||
|
||||
/* did we find something to do? */
|
||||
if (tr == NULL)
|
||||
break;
|
||||
|
||||
/* try to give command to controller */
|
||||
error = twe_start(tr);
|
||||
|
||||
if (error != 0) {
|
||||
if (error == EBUSY) {
|
||||
twe_requeue_ready(tr); /* try it again later */
|
||||
break; /* don't try anything more for now */
|
||||
}
|
||||
/* otherwise, fail the command */
|
||||
tr->tr_status = TWE_CMD_FAILED;
|
||||
twe_completeio(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Handle completion of an I/O command.
|
||||
*/
|
||||
static void
|
||||
twe_completeio(struct twe_request *tr)
|
||||
{
|
||||
TWE_Command *cmd = &tr->tr_command;
|
||||
struct twe_softc *sc = tr->tr_sc;
|
||||
twe_bio *bp = (twe_bio *)tr->tr_private;
|
||||
|
||||
@ -893,36 +891,15 @@ twe_completeio(struct twe_request *tr)
|
||||
|
||||
if (tr->tr_status == TWE_CMD_COMPLETE) {
|
||||
|
||||
switch (cmd->generic.flags) {
|
||||
case TWE_FLAGS_SUCCESS:
|
||||
break;
|
||||
case TWE_FLAGS_INFORMATIONAL:
|
||||
case TWE_FLAGS_WARNING:
|
||||
twe_printf(sc, "command completed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
break;
|
||||
|
||||
case TWE_FLAGS_FATAL:
|
||||
default:
|
||||
twe_printf(sc, "command failed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
if (twe_report_request(tr))
|
||||
TWE_BIO_SET_ERROR(bp, EIO);
|
||||
|
||||
/*
|
||||
* XXX some status values suggest that the controller should be reset and all outstanding
|
||||
* commands retried. This might be a good place for that.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} else if (tr->tr_status == TWE_CMD_FAILED) { /* could be more verbose here? */
|
||||
TWE_BIO_SET_ERROR(bp, EIO);
|
||||
twe_printf(sc, "command failed submission - controller wedged\n");
|
||||
/*
|
||||
* XXX reset controller and retry?
|
||||
*/
|
||||
} else {
|
||||
twe_panic(sc, "twe_completeio on incomplete command");
|
||||
}
|
||||
twe_release_request(tr);
|
||||
tr->tr_private = NULL;
|
||||
twed_intr(bp);
|
||||
twe_release_request(tr);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -935,7 +912,7 @@ twe_reset(struct twe_softc *sc)
|
||||
struct twe_request *tr;
|
||||
int i, s;
|
||||
|
||||
twe_printf(sc, "Controller reset in progress...\n");
|
||||
twe_printf(sc, "controller reset in progress...\n");
|
||||
|
||||
/*
|
||||
* Disable interrupts from the controller, and mask any accidental entry
|
||||
@ -1075,15 +1052,14 @@ twe_done(struct twe_softc *sc)
|
||||
found = 1;
|
||||
rq = TWE_RESPONSE_QUEUE(sc);
|
||||
tr = sc->twe_lookup[rq.u.response_id]; /* find command */
|
||||
if (tr != NULL) { /* paranoia */
|
||||
debug(3, "completed request id %d with status %d",
|
||||
tr->tr_command.generic.request_id, tr->tr_command.generic.status);
|
||||
/* move to completed queue */
|
||||
twe_remove_busy(tr);
|
||||
twe_enqueue_complete(tr);
|
||||
} else {
|
||||
debug(2, "done event for nonbusy id %d\n", rq.u.response_id);
|
||||
}
|
||||
if (tr->tr_status != TWE_CMD_BUSY)
|
||||
twe_printf(sc, "completion event for nonbusy command\n");
|
||||
tr->tr_status = TWE_CMD_COMPLETE;
|
||||
debug(3, "completed request id %d with status %d",
|
||||
tr->tr_command.generic.request_id, tr->tr_command.generic.status);
|
||||
/* move to completed queue */
|
||||
twe_remove_busy(tr);
|
||||
twe_enqueue_complete(tr);
|
||||
} else {
|
||||
break; /* no response ready */
|
||||
}
|
||||
@ -1119,9 +1095,6 @@ twe_complete(struct twe_softc *sc)
|
||||
/* unmap the command's data buffer */
|
||||
twe_unmap_request(tr);
|
||||
|
||||
/* mark command as complete */
|
||||
tr->tr_status = TWE_CMD_COMPLETE;
|
||||
|
||||
/* dispatch to suit command originator */
|
||||
if (tr->tr_complete != NULL) { /* completion callback */
|
||||
debug(2, "call completion handler %p", tr->tr_complete);
|
||||
@ -1483,6 +1456,7 @@ twe_get_request(struct twe_softc *sc, struct twe_request **tr)
|
||||
/* initialise some fields to their defaults */
|
||||
if (*tr != NULL) {
|
||||
(*tr)->tr_data = NULL;
|
||||
(*tr)->tr_private = NULL;
|
||||
(*tr)->tr_status = TWE_CMD_SETUP; /* command is in setup phase */
|
||||
(*tr)->tr_flags = 0;
|
||||
(*tr)->tr_complete = NULL;
|
||||
@ -1501,6 +1475,8 @@ twe_release_request(struct twe_request *tr)
|
||||
{
|
||||
debug_called(4);
|
||||
|
||||
if (tr->tr_private != NULL)
|
||||
twe_panic(tr->tr_sc, "tr_private != NULL");
|
||||
twe_enqueue_free(tr);
|
||||
}
|
||||
|
||||
@ -1653,18 +1629,47 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen)
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Print a diagnostic if the status of the command warrants it, and return
|
||||
* either zero (command was ok) or nonzero (command failed).
|
||||
*/
|
||||
static int
|
||||
twe_request_qlen(struct twe_request *tr)
|
||||
twe_report_request(struct twe_request *tr)
|
||||
{
|
||||
int len = 0;
|
||||
struct twe_softc *sc = tr->tr_sc;
|
||||
TWE_Command *cmd = &tr->tr_command;
|
||||
int result;
|
||||
|
||||
while (tr != NULL) {
|
||||
tr = TAILQ_NEXT(tr, tr_link);
|
||||
len++;
|
||||
switch (cmd->generic.flags) {
|
||||
case TWE_FLAGS_SUCCESS:
|
||||
result = 0;
|
||||
break;
|
||||
case TWE_FLAGS_INFORMATIONAL:
|
||||
case TWE_FLAGS_WARNING:
|
||||
twe_printf(sc, "command completed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case TWE_FLAGS_FATAL:
|
||||
default:
|
||||
twe_printf(sc, "command failed - %s\n",
|
||||
twe_describe_code(twe_table_status, cmd->generic.status));
|
||||
result = 1;
|
||||
|
||||
/*
|
||||
* The status code 0xff requests a controller reset
|
||||
*/
|
||||
if (cmd->generic.status == 0xff)
|
||||
twe_reset(sc);
|
||||
break;
|
||||
}
|
||||
return(len);
|
||||
return(result);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Print some controller state to aid in debugging error/panic conditions
|
||||
*/
|
||||
void
|
||||
twe_print_controller(struct twe_softc *sc)
|
||||
{
|
||||
@ -1672,10 +1677,12 @@ twe_print_controller(struct twe_softc *sc)
|
||||
|
||||
status_reg = TWE_STATUS(sc);
|
||||
twe_printf(sc, "status %b\n", status_reg, TWE_STATUS_BITS_DESCRIPTION);
|
||||
twe_printf(sc, "free %d\n", twe_request_qlen(TAILQ_FIRST(&sc->twe_free)));
|
||||
twe_printf(sc, "ready %d\n", twe_request_qlen(TAILQ_FIRST(&sc->twe_ready)));
|
||||
twe_printf(sc, "busy %d\n", twe_request_qlen(TAILQ_FIRST(&sc->twe_busy)));
|
||||
twe_printf(sc, "complete %d\n", twe_request_qlen(TAILQ_FIRST(&sc->twe_complete)));
|
||||
twe_printf(sc, " current max\n");
|
||||
twe_printf(sc, "free %04d %04d\n", sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max);
|
||||
twe_printf(sc, "ready %04d %04d\n", sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max);
|
||||
twe_printf(sc, "busy %04d %04d\n", sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max);
|
||||
twe_printf(sc, "complete %04d %04d\n", sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max);
|
||||
twe_printf(sc, "bioq %04d %04d\n", sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max);
|
||||
twe_printf(sc, "AEN queue head %d tail %d\n", sc->twe_aen_head, sc->twe_aen_tail);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,13 @@
|
||||
* FreeBSD-specific code.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/cons.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <dev/twe/twe_compat.h>
|
||||
#include <dev/twe/twereg.h>
|
||||
#include <dev/twe/tweio.h>
|
||||
@ -41,6 +48,16 @@
|
||||
|
||||
static devclass_t twe_devclass;
|
||||
|
||||
#ifdef TWE_DEBUG
|
||||
static u_int32_t twed_bio_in;
|
||||
#define TWED_BIO_IN twed_bio_in++
|
||||
static u_int32_t twed_bio_out;
|
||||
#define TWED_BIO_OUT twed_bio_out++
|
||||
#else
|
||||
#define TWED_BIO_IN
|
||||
#define TWED_BIO_OUT
|
||||
#endif
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
Control device interface
|
||||
@ -250,13 +267,13 @@ twe_attach(device_t dev)
|
||||
/*
|
||||
* Create DMA tag for mapping objects into controller-addressable space.
|
||||
*/
|
||||
if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */
|
||||
1, 0, /* alignment, boundary */
|
||||
if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */
|
||||
1, 0, /* alignment, boundary */
|
||||
BUS_SPACE_MAXADDR, /* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */
|
||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||
MAXBSIZE, TWE_MAX_SGL_LENGTH,/* maxsize, nsegments */
|
||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||
0, /* flags */
|
||||
&sc->twe_buffer_dmat)) {
|
||||
twe_printf(sc, "can't allocate data buffer DMA tag\n");
|
||||
@ -551,6 +568,7 @@ DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0);
|
||||
static d_open_t twed_open;
|
||||
static d_close_t twed_close;
|
||||
static d_strategy_t twed_strategy;
|
||||
static d_dump_t twed_dump;
|
||||
|
||||
#define TWED_CDEV_MAJOR 147
|
||||
|
||||
@ -565,7 +583,7 @@ static struct cdevsw twed_cdevsw = {
|
||||
twed_strategy,
|
||||
"twed",
|
||||
TWED_CDEV_MAJOR,
|
||||
nodump,
|
||||
twed_dump,
|
||||
nopsize,
|
||||
D_DISK,
|
||||
-1
|
||||
@ -639,9 +657,14 @@ twed_strategy(twe_bio *bp)
|
||||
|
||||
debug_called(4);
|
||||
|
||||
TWED_BIO_IN;
|
||||
|
||||
/* bogus disk? */
|
||||
if (sc == NULL) {
|
||||
TWE_BIO_SET_ERROR(bp, EINVAL);
|
||||
printf("twe: bio for invalid disk!\n");
|
||||
TWE_BIO_DONE(bp);
|
||||
TWED_BIO_OUT;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -649,17 +672,81 @@ twed_strategy(twe_bio *bp)
|
||||
if (TWE_BIO_LENGTH(bp) == 0) {
|
||||
TWE_BIO_RESID(bp) = 0;
|
||||
TWE_BIO_DONE(bp);
|
||||
TWED_BIO_OUT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* perform accounting */
|
||||
TWE_BIO_STATS_START(bp);
|
||||
|
||||
/* pass the bio to the controller - it can work out who we are */
|
||||
twe_submit_bio(sc->twed_controller, bp);
|
||||
/* queue the bio on the controller */
|
||||
twe_enqueue_bio(sc->twed_controller, bp);
|
||||
|
||||
/* poke the controller to start I/O */
|
||||
twe_startio(sc->twed_controller);
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* System crashdump support
|
||||
*/
|
||||
int
|
||||
twed_dump(dev_t dev)
|
||||
{
|
||||
struct twed_softc *twed_sc = (struct twed_softc *)dev->si_drv1;
|
||||
struct twe_softc *twe_sc = (struct twe_softc *)twed_sc->twed_controller;
|
||||
u_int count, blkno, secsize;
|
||||
vm_offset_t addr = 0;
|
||||
long blkcnt;
|
||||
int dumppages = MAXDUMPPGS;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
|
||||
return(error);
|
||||
|
||||
if (!twed_sc || !twe_sc)
|
||||
return(ENXIO);
|
||||
|
||||
blkcnt = howmany(PAGE_SIZE, secsize);
|
||||
|
||||
while (count > 0) {
|
||||
caddr_t va = NULL;
|
||||
|
||||
if ((count / blkcnt) < dumppages)
|
||||
dumppages = count / blkcnt;
|
||||
|
||||
for (i = 0; i < dumppages; ++i) {
|
||||
vm_offset_t a = addr + (i * PAGE_SIZE);
|
||||
if (is_physical_memory(a))
|
||||
va = pmap_kenter_temporary(trunc_page(a), i);
|
||||
else
|
||||
va = pmap_kenter_temporary(trunc_page(0), i);
|
||||
}
|
||||
|
||||
if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_unit, blkno, va,
|
||||
(PAGE_SIZE * dumppages) / TWE_BLOCK_SIZE)) != 0)
|
||||
return(error);
|
||||
|
||||
|
||||
if (addr % (1024 * 1024) == 0) {
|
||||
#ifdef HW_WDOG
|
||||
if (wdog_tickler)
|
||||
(*wdog_tickler)();
|
||||
#endif
|
||||
printf("%ld ", (long)(count * DEV_BSIZE) / (1024 * 1024));
|
||||
}
|
||||
|
||||
blkno += blkcnt * dumppages;
|
||||
count -= blkcnt * dumppages;
|
||||
addr += PAGE_SIZE * dumppages;
|
||||
|
||||
if (cncheckc() != -1)
|
||||
return(EINTR);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Handle completion of an I/O request.
|
||||
*/
|
||||
@ -674,6 +761,7 @@ twed_intr(twe_bio *bp)
|
||||
|
||||
TWE_BIO_STATS_END(bp);
|
||||
TWE_BIO_DONE(bp);
|
||||
TWED_BIO_OUT;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -967,6 +1055,7 @@ twe_report(void)
|
||||
s = splbio();
|
||||
for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++)
|
||||
twe_print_controller(sc);
|
||||
printf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out);
|
||||
splx(s);
|
||||
}
|
||||
#endif
|
||||
|
@ -84,7 +84,6 @@ 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_FAILED 3 /* failed submission to controller */
|
||||
int tr_flags;
|
||||
#define TWE_CMD_DATAIN (1<<0)
|
||||
#define TWE_CMD_DATAOUT (1<<1)
|
||||
@ -122,9 +121,7 @@ struct twe_softc
|
||||
#define TWE_STATE_OPEN (1<<2) /* control device is open */
|
||||
#define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */
|
||||
int twe_host_id;
|
||||
#ifdef TWE_PERFORMANCE_MONITOR
|
||||
struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */
|
||||
#endif
|
||||
|
||||
TWE_PLATFORM_SOFTC /* platform-specific softc elements */
|
||||
};
|
||||
@ -136,8 +133,9 @@ extern int twe_setup(struct twe_softc *sc); /* do early driver/controller setup
|
||||
extern void twe_init(struct twe_softc *sc); /* init controller */
|
||||
extern void twe_deinit(struct twe_softc *sc); /* stop controller */
|
||||
extern void twe_intr(struct twe_softc *sc); /* hardware interrupt signalled */
|
||||
extern int twe_submit_bio(struct twe_softc *sc,
|
||||
twe_bio *bp); /* pass bio to core */
|
||||
extern void twe_startio(struct twe_softc *sc);
|
||||
extern int twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */
|
||||
u_int32_t lba, void *data, int nblks);
|
||||
extern int twe_ioctl(struct twe_softc *sc, int cmd,
|
||||
void *addr); /* handle user request */
|
||||
extern void twe_describe_controller(struct twe_softc *sc); /* print controller info */
|
||||
@ -156,8 +154,7 @@ extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer
|
||||
/********************************************************************************
|
||||
* Queue primitives
|
||||
*/
|
||||
#ifdef TWE_PERFORMANCE_MONITOR
|
||||
# define TWEQ_ADD(sc, qname) \
|
||||
#define TWEQ_ADD(sc, qname) \
|
||||
do { \
|
||||
struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \
|
||||
\
|
||||
@ -166,17 +163,12 @@ extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer
|
||||
qs->q_max = qs->q_length; \
|
||||
} while(0)
|
||||
|
||||
# define TWEQ_REMOVE(sc, qname) (sc)->twe_qstat[qname].q_length--
|
||||
# define TWEQ_INIT(sc, qname) \
|
||||
#define TWEQ_REMOVE(sc, qname) (sc)->twe_qstat[qname].q_length--
|
||||
#define TWEQ_INIT(sc, qname) \
|
||||
do { \
|
||||
sc->twe_qstat[qname].q_length = 0; \
|
||||
sc->twe_qstat[qname].q_max = 0; \
|
||||
} while(0)
|
||||
#else
|
||||
# define TWEQ_ADD(sc, qname)
|
||||
# define TWEQ_REMOVE(sc, qname)
|
||||
# define TWEQ_INIT(sc, qname)
|
||||
#endif
|
||||
|
||||
|
||||
#define TWEQ_REQUEST_QUEUE(name, index) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user