summaryrefslogtreecommitdiffstats
path: root/sys/dev/twe/twe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/twe/twe.c')
-rw-r--r--sys/dev/twe/twe.c148
1 files changed, 100 insertions, 48 deletions
diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c
index 1ffb7b2..32cc61d 100644
--- a/sys/dev/twe/twe.c
+++ b/sys/dev/twe/twe.c
@@ -1,5 +1,7 @@
/*-
* Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
* Copyright (c) 2000 BSDi
* All rights reserved.
*
@@ -60,8 +62,8 @@ static int twe_wait_request(struct twe_request *tr);
static int twe_immediate_request(struct twe_request *tr);
static void twe_completeio(struct twe_request *tr);
static void twe_reset(struct twe_softc *sc);
-static void twe_add_unit(struct twe_softc *sc, int unit);
-static void twe_del_unit(struct twe_softc *sc, int unit);
+static int twe_add_unit(struct twe_softc *sc, int unit);
+static int twe_del_unit(struct twe_softc *sc, int unit);
/*
* Command I/O to controller.
@@ -86,7 +88,7 @@ static void twe_command_intr(struct twe_softc *sc);
static int twe_fetch_aen(struct twe_softc *sc);
static void twe_handle_aen(struct twe_request *tr);
static void twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen);
-static int twe_dequeue_aen(struct twe_softc *sc);
+static u_int16_t twe_dequeue_aen(struct twe_softc *sc);
static int twe_drain_aen_queue(struct twe_softc *sc);
static int twe_find_aen(struct twe_softc *sc, u_int16_t aen);
@@ -192,17 +194,17 @@ twe_setup(struct twe_softc *sc)
return(0);
}
-static void
+static int
twe_add_unit(struct twe_softc *sc, int unit)
{
struct twe_drive *dr;
- int table;
+ int table, error = 0;
u_int16_t dsize;
TWE_Param *drives = NULL, *param = NULL;
TWE_Unit_Descriptor *ud;
if (unit < 0 || unit > TWE_MAX_UNITS)
- return;
+ return (EINVAL);
/*
* The controller is in a safe state, so try to find drives attached to it.
@@ -210,30 +212,36 @@ twe_add_unit(struct twe_softc *sc, int unit)
if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status,
TWE_MAX_UNITS, NULL)) == NULL) {
twe_printf(sc, "can't detect attached units\n");
- return;
+ return (EIO);
}
dr = &sc->twe_drive[unit];
/* check that the drive is online */
- if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online))
+ if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online)) {
+ error = ENXIO;
goto out;
+ }
table = TWE_PARAM_UNITINFO + unit;
if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
twe_printf(sc, "error fetching capacity for unit %d\n", unit);
+ error = EIO;
goto out;
}
if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) {
twe_printf(sc, "error fetching state for unit %d\n", unit);
+ error = EIO;
goto out;
}
if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) {
twe_printf(sc, "error fetching descriptor size for unit %d\n", unit);
+ error = EIO;
goto out;
}
if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) {
twe_printf(sc, "error fetching descriptor for unit %d\n", unit);
+ error = EIO;
goto out;
}
ud = (TWE_Unit_Descriptor *)param->data;
@@ -248,25 +256,31 @@ twe_add_unit(struct twe_softc *sc, int unit)
dr->td_sectors = 32;
}
dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
- dr->td_unit = unit;
+ dr->td_twe_unit = unit;
- twe_attach_drive(sc, dr);
+ error = twe_attach_drive(sc, dr);
out:
if (param != NULL)
free(param, M_DEVBUF);
if (drives != NULL)
free(drives, M_DEVBUF);
+ return (error);
}
-static void
+static int
twe_del_unit(struct twe_softc *sc, int unit)
{
+ int error;
if (unit < 0 || unit > TWE_MAX_UNITS)
- return;
+ return (ENXIO);
- twe_detach_drive(sc, unit);
+ if (sc->twe_drive[unit].td_disk == NULL)
+ return (ENXIO);
+
+ error = twe_detach_drive(sc, unit);
+ return (error);
}
/********************************************************************************
@@ -477,7 +491,7 @@ twe_ioctl(struct twe_softc *sc, int ioctlcmd, void *addr)
TWE_Param *param;
TWE_Command *cmd;
void *data;
- int *arg = (int *)addr;
+ u_int16_t *aen_code = (u_int16_t *)addr;
struct twe_request *tr;
u_int8_t srid;
int s, error;
@@ -553,13 +567,13 @@ twe_ioctl(struct twe_softc *sc, int ioctlcmd, void *addr)
/* poll for an AEN */
case TWEIO_AEN_POLL:
- *arg = twe_dequeue_aen(sc);
+ *aen_code = twe_dequeue_aen(sc);
break;
/* wait for another AEN to show up */
case TWEIO_AEN_WAIT:
s = splbio();
- while ((*arg = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
+ while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
error = tsleep(&sc->twe_aen_queue, PRIBIO | PCATCH, "tweaen", 0);
if (error == EINTR)
break;
@@ -600,11 +614,11 @@ twe_ioctl(struct twe_softc *sc, int ioctlcmd, void *addr)
break;
case TWEIO_ADD_UNIT:
- twe_add_unit(sc, td->td_unit);
+ error = twe_add_unit(sc, td->td_unit);
break;
case TWEIO_DEL_UNIT:
- twe_del_unit(sc, td->td_unit);
+ error = twe_del_unit(sc, td->td_unit);
break;
/* XXX implement ATA PASSTHROUGH */
@@ -735,6 +749,8 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz
if (error == 0) {
if (twe_report_request(tr))
goto err;
+ } else {
+ goto err;
}
twe_release_request(tr);
return(param);
@@ -924,6 +940,7 @@ twe_immediate_request(struct twe_request *tr)
static void
twe_completeio(struct twe_request *tr)
{
+ TWE_Command *cmd = TWE_FIND_COMMAND(tr);
struct twe_softc *sc = tr->tr_sc;
twe_bio *bp = (twe_bio *)tr->tr_private;
@@ -931,8 +948,9 @@ twe_completeio(struct twe_request *tr)
if (tr->tr_status == TWE_CMD_COMPLETE) {
- if (twe_report_request(tr))
- TWE_BIO_SET_ERROR(bp, EIO);
+ if (cmd->generic.status)
+ if (twe_report_request(tr))
+ TWE_BIO_SET_ERROR(bp, EIO);
} else {
twe_panic(sc, "twe_completeio on incomplete command");
@@ -1299,7 +1317,6 @@ twe_command_intr(struct twe_softc *sc)
* them, and when other commands have completed. Mask it so we don't get
* another one.
*/
- twe_printf(sc, "command interrupt\n");
TWE_CONTROL(sc, TWE_CONTROL_MASK_COMMAND_INTERRUPT);
}
@@ -1416,10 +1433,10 @@ twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen)
*
* We are more or less interrupt-safe, so don't block interrupts.
*/
-static int
+static u_int16_t
twe_dequeue_aen(struct twe_softc *sc)
{
- int result;
+ u_int16_t result;
debug_called(4);
@@ -1556,23 +1573,33 @@ twe_describe_controller(struct twe_softc *sc)
twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports);
/* get version strings */
- p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon, 16, NULL);
- p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW, 16, NULL);
- p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL);
- p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB, 8, NULL);
- p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA, 8, NULL);
- p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI, 8, NULL);
-
- twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[1]->data, p[2]->data);
- if (bootverbose)
- twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[0]->data, p[3]->data,
- p[4]->data, p[5]->data);
- free(p[0], M_DEVBUF);
- free(p[1], M_DEVBUF);
- free(p[2], M_DEVBUF);
- free(p[3], M_DEVBUF);
- free(p[4], M_DEVBUF);
- free(p[5], M_DEVBUF);
+ p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW, 16, NULL);
+ p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL);
+ if (p[0] && p[1])
+ twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[0]->data, p[1]->data);
+
+ if (bootverbose) {
+ p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon, 16, NULL);
+ p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB, 8, NULL);
+ p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA, 8, NULL);
+ p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI, 8, NULL);
+
+ if (p[2] && p[3] && p[4] && p[5])
+ twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[2]->data, p[3]->data,
+ p[4]->data, p[5]->data);
+ if (p[2])
+ free(p[2], M_DEVBUF);
+ if (p[3])
+ free(p[3], M_DEVBUF);
+ if (p[4])
+ free(p[4], M_DEVBUF);
+ if (p[5])
+ free(p[5], M_DEVBUF);
+ }
+ if (p[0])
+ free(p[0], M_DEVBUF);
+ if (p[1])
+ free(p[1], M_DEVBUF);
/* print attached drives */
if (bootverbose) {
@@ -1589,11 +1616,26 @@ twe_describe_controller(struct twe_softc *sc)
twe_printf(sc, "port %d, drive status unavailable\n", i);
}
}
- free(p[0], M_DEVBUF);
+ if (p[0])
+ free(p[0], M_DEVBUF);
}
}
/********************************************************************************
+ * Look up a text description of a numeric code and return a pointer to same.
+ */
+char *
+twe_describe_code(struct twe_code_lookup *table, u_int32_t code)
+{
+ int i;
+
+ for (i = 0; table[i].string != NULL; i++)
+ if (table[i].code == code)
+ return(table[i].string);
+ return(table[i+1].string);
+}
+
+/********************************************************************************
* Complain if the status bits aren't what we're expecting.
*
* Rate-limit the complaints to at most one of each every five seconds, but
@@ -1714,7 +1756,7 @@ twe_report_request(struct twe_request *tr)
/*
* The status code 0xff requests a controller reset.
*/
- twe_printf(sc, "command returned with controller rest request\n");
+ twe_printf(sc, "command returned with controller reset request\n");
twe_reset(sc);
result = 1;
} else if (cmd->generic.status > TWE_STATUS_FATAL) {
@@ -1770,12 +1812,22 @@ 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, " 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, " current max min\n");
+ twe_printf(sc, "free %04d %04d %04d\n",
+ sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max, sc->twe_qstat[TWEQ_FREE].q_min);
+
+ twe_printf(sc, "ready %04d %04d %04d\n",
+ sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max, sc->twe_qstat[TWEQ_READY].q_min);
+
+ twe_printf(sc, "busy %04d %04d %04d\n",
+ sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max, sc->twe_qstat[TWEQ_BUSY].q_min);
+
+ twe_printf(sc, "complete %04d %04d %04d\n",
+ sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max, sc->twe_qstat[TWEQ_COMPLETE].q_min);
+
+ twe_printf(sc, "bioq %04d %04d %04d\n",
+ sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max, sc->twe_qstat[TWEQ_BIO].q_min);
+
twe_printf(sc, "AEN queue head %d tail %d\n", sc->twe_aen_head, sc->twe_aen_tail);
}
OpenPOWER on IntegriCloud