summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/twe/twe.c70
-rw-r--r--sys/dev/twe/twe_freebsd.c30
-rw-r--r--sys/dev/twe/twe_tables.h20
-rw-r--r--sys/dev/twe/twereg.h30
-rw-r--r--sys/dev/twe/twevar.h2
5 files changed, 132 insertions, 20 deletions
diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c
index a8d7164..75c0808 100644
--- a/sys/dev/twe/twe.c
+++ b/sys/dev/twe/twe.c
@@ -115,6 +115,7 @@ int
twe_setup(struct twe_softc *sc)
{
struct twe_request *tr;
+ u_int32_t status_reg;
int i;
debug_called(4);
@@ -149,6 +150,12 @@ twe_setup(struct twe_softc *sc)
}
/*
+ * Check status register for errors, clear them.
+ */
+ status_reg = TWE_STATUS(sc);
+ twe_check_bits(sc, status_reg);
+
+ /*
* Wait for the controller to come ready.
*/
if (twe_wait_status(sc, TWE_STATUS_MICROCONTROLLER_READY, 60)) {
@@ -566,6 +573,8 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
twe_reset(sc);
break;
+ /* XXX implement ATA PASSTHROUGH */
+
/* nothing we understand */
default:
error = ENOTTY;
@@ -919,12 +928,16 @@ twe_reset(struct twe_softc *sc)
struct twe_request *tr;
int i, s;
- twe_printf(sc, "controller reset in progress...\n");
+ /*
+ * Sleep for a short period to allow AENs to be signalled.
+ */
+ tsleep(NULL, PRIBIO, "twereset", hz);
/*
* Disable interrupts from the controller, and mask any accidental entry
* into our interrupt handler.
*/
+ twe_printf(sc, "controller reset in progress...\n");
twe_disable_interrupts(sc);
s = splbio();
@@ -1178,10 +1191,11 @@ twe_soft_reset(struct twe_softc *sc)
TWE_SOFT_RESET(sc);
- if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 15)) {
+ if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 30)) {
twe_printf(sc, "no attention interrupt\n");
return(1);
}
+ TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT);
if (twe_drain_aen_queue(sc)) {
twe_printf(sc, "can't drain AEN queue\n");
return(1);
@@ -1586,6 +1600,14 @@ twe_check_bits(struct twe_softc *sc, u_int32_t status_reg)
lastwarn[1] = time_second;
}
result = 1;
+ if (status_reg & TWE_STATUS_PCI_PARITY_ERROR) {
+ twe_printf(sc, "PCI parity error: Reseat card, move card or buggy device present.");
+ twe_clear_pci_parity_error(sc);
+ }
+ if (status_reg & TWE_STATUS_PCI_ABORT) {
+ twe_printf(sc, "PCI abort, clearing.");
+ twe_clear_pci_abort(sc);
+ }
}
return(result);
@@ -1616,7 +1638,7 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen)
if (!bootverbose)
return(NULL);
/* FALLTHROUGH */
- case 'p':
+ case 'a':
return(msg);
case 'c':
@@ -1627,6 +1649,12 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen)
msg, TWE_AEN_UNIT(aen));
}
return(buf);
+
+ case 'p':
+ sprintf(buf, "twe%d: port %d: %s", device_get_unit(sc->twe_dev), TWE_AEN_UNIT(aen),
+ msg);
+ return(buf);
+
case 'x':
default:
@@ -1660,25 +1688,41 @@ twe_report_request(struct twe_request *tr)
} else if (cmd->generic.status > TWE_STATUS_FATAL) {
/*
* Fatal errors that don't require controller reset.
+ *
+ * We know a few special flags values.
*/
- twe_printf(sc, "command returned fatal status - %s (flags = 0x%x)\n",
- twe_describe_code(twe_table_status, cmd->generic.status),
- cmd->generic.flags);
- result = 1;
+ switch (cmd->generic.flags) {
+ case 0x1b:
+ device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
+ "drive timeout");
+ break;
+ case 0x51:
+ device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
+ "unrecoverable drive error");
+ break;
+ default:
+ device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
+ "controller error - %s (flags = 0x%x)\n",
+ twe_describe_code(twe_table_status, cmd->generic.status),
+ cmd->generic.flags);
+ result = 1;
+ }
} else if (cmd->generic.status > TWE_STATUS_WARNING) {
/*
* Warning level status.
*/
- twe_printf(sc, "command returned warning status - %s (flags = 0x%x)\n",
- twe_describe_code(twe_table_status, cmd->generic.status),
- cmd->generic.flags);
+ device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
+ "warning - %s (flags = 0x%x)\n",
+ twe_describe_code(twe_table_status, cmd->generic.status),
+ cmd->generic.flags);
} else if (cmd->generic.status > 0x40) {
/*
* Info level status.
*/
- twe_printf(sc, "command returned info status: %s (flags = 0x%x)\n",
- twe_describe_code(twe_table_status, cmd->generic.status),
- cmd->generic.flags);
+ device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
+ "attention - %s (flags = 0x%x)\n",
+ twe_describe_code(twe_table_status, cmd->generic.status),
+ cmd->generic.flags);
}
return(result);
diff --git a/sys/dev/twe/twe_freebsd.c b/sys/dev/twe/twe_freebsd.c
index 242950d..1fffe4e 100644
--- a/sys/dev/twe/twe_freebsd.c
+++ b/sys/dev/twe/twe_freebsd.c
@@ -90,7 +90,7 @@ static struct cdevsw twe_cdevsw = {
* Accept an open operation on the control device.
*/
static int
-twe_open(dev_t dev, int flags, int fmt, struct thread *td)
+twe_open(dev_t dev, int flags, int fmt, d_thread_t *td)
{
int unit = minor(dev);
struct twe_softc *sc = devclass_get_softc(twe_devclass, unit);
@@ -103,7 +103,7 @@ twe_open(dev_t dev, int flags, int fmt, struct thread *td)
* Accept the last close on the control device.
*/
static int
-twe_close(dev_t dev, int flags, int fmt, struct thread *td)
+twe_close(dev_t dev, int flags, int fmt, d_thread_t *td)
{
int unit = minor(dev);
struct twe_softc *sc = devclass_get_softc(twe_devclass, unit);
@@ -116,7 +116,7 @@ twe_close(dev_t dev, int flags, int fmt, struct thread *td)
* Handle controller-specific control operations.
*/
static int
-twe_ioctl_wrapper(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
+twe_ioctl_wrapper(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
{
struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
@@ -513,6 +513,26 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
}
/********************************************************************************
+ * Clear a PCI parity error.
+ */
+void
+twe_clear_pci_parity_error(struct twe_softc *sc)
+{
+ TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PARITY_ERROR);
+ pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PARITY_ERROR, 2);
+}
+
+/********************************************************************************
+ * Clear a PCI abort.
+ */
+void
+twe_clear_pci_abort(struct twe_softc *sc)
+{
+ TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PCI_ABORT);
+ pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PCI_ABORT, 2);
+}
+
+/********************************************************************************
********************************************************************************
Disk device
********************************************************************************
@@ -599,7 +619,7 @@ static int disks_registered = 0;
* for opens on subdevices (eg. slices, partitions).
*/
static int
-twed_open(dev_t dev, int flags, int fmt, struct thread *td)
+twed_open(dev_t dev, int flags, int fmt, d_thread_t *td)
{
struct twed_softc *sc = (struct twed_softc *)dev->si_drv1;
struct disklabel *label;
@@ -632,7 +652,7 @@ twed_open(dev_t dev, int flags, int fmt, struct thread *td)
* Handle last close of the disk device.
*/
static int
-twed_close(dev_t dev, int flags, int fmt, struct thread *td)
+twed_close(dev_t dev, int flags, int fmt, d_thread_t *td)
{
struct twed_softc *sc = (struct twed_softc *)dev->si_drv1;
diff --git a/sys/dev/twe/twe_tables.h b/sys/dev/twe/twe_tables.h
index aa1ab02..116a8da 100644
--- a/sys/dev/twe/twe_tables.h
+++ b/sys/dev/twe/twe_tables.h
@@ -118,7 +118,7 @@ struct twe_code_lookup twe_table_aen[] = {
{"q queue empty", 0x00},
{"q soft reset", 0x01},
{"c degraded mirror", 0x02},
- {"p controller error", 0x03},
+ {"a controller error", 0x03},
{"c rebuild fail", 0x04},
{"c rebuild done", 0x05},
{"c incomplete unit", 0x06},
@@ -127,7 +127,23 @@ struct twe_code_lookup twe_table_aen[] = {
{"c drive timeout", 0x09},
{"c drive error", 0x0a},
{"c rebuild started", 0x0b},
- {"p aen queue full", 0xff},
+ {"c init started", 0x0c},
+ {"c logical unit deleted", 0x0d},
+ {"p SMART threshold exceeded", 0x0f},
+ {"p ATA UDMA downgrade", 0x21},
+ {"p ATA UDMA upgrade", 0x22},
+ {"p sector repair occurred", 0x23},
+ {"a SBUF integrity check failure", 0x24},
+ {"p lost cached write", 0x25},
+ {"p drive ECC error detected", 0x26},
+ {"p DCB checksum error", 0x27},
+ {"p DCB unsupported version", 0x28},
+ {"c verify started", 0x29},
+ {"c verify failed", 0x2a},
+ {"c verify complete", 0x2b},
+ {"p overwrote bad sector during rebuild", 0x2c},
+ {"p encountered bad sector during rebuild", 0x2d},
+ {"a aen queue full", 0xff},
{NULL, 0},
{"x unknown AEN", 0}
};
diff --git a/sys/dev/twe/twereg.h b/sys/dev/twe/twereg.h
index e7136df..12ce0d6 100644
--- a/sys/dev/twe/twereg.h
+++ b/sys/dev/twe/twereg.h
@@ -47,6 +47,8 @@
#define TWE_CONTROL_ENABLE_INTERRUPTS 0x00000080
#define TWE_CONTROL_DISABLE_INTERRUPTS 0x00000040
#define TWE_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
+#define TWE_CONTROL_CLEAR_PARITY_ERROR 0x00800000
+#define TWE_CONTROL_CLEAR_PCI_ABORT 0x00100000
#define TWE_SOFT_RESET(sc) TWE_CONTROL(sc, TWE_CONTROL_ISSUE_SOFT_RESET | \
TWE_CONTROL_CLEAR_HOST_INTERRUPT | \
@@ -100,6 +102,8 @@
#define TWE_VENDOR_ID 0x13C1
#define TWE_DEVICE_ID 0x1000
#define TWE_DEVICE_ID_ASIC 0x1001
+#define TWE_PCI_CLEAR_PARITY_ERROR 0xc100
+#define TWE_PCI_CLEAR_PCI_ABORT 0x2000
/* command packet opcodes */
#define TWE_OP_NOP 0x00
@@ -123,6 +127,8 @@
#define TWE_OP_SECTOR_INFO 0x1a
#define TWE_OP_AEN_LISTEN 0x1c
#define TWE_OP_CMD_PACKET 0x1d
+#define TWE_OP_ATA_PASSTHROUGH 0x1e
+#define TWE_OP_CMD_WITH_DATA 0x1f
/* command status values */
#define TWE_STATUS_RESET 0xff /* controller requests reset */
@@ -138,6 +144,8 @@
#define TWE_SHUTDOWN_MESSAGE_CREDITS 0x001
#define TWE_INIT_COMMAND_PACKET_SIZE 0x3
#define TWE_MAX_SGL_LENGTH 62
+#define TWE_MAX_ATA_SGL_LENGTH 60
+#define TWE_MAX_PASSTHROUGH 4096
#define TWE_Q_LENGTH TWE_INIT_MESSAGE_CREDITS
#define TWE_Q_START 0
#define TWE_MAX_RESET_TRIES 3
@@ -272,6 +280,26 @@ typedef struct
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
+ u_int16_t param;
+ u_int16_t features;
+ u_int16_t sector_count;
+ u_int16_t sector_num;
+ u_int16_t cylinder_lo;
+ u_int16_t cylinder_hi;
+ u_int8_t drive_head;
+ u_int8_t command;
+ TWE_SG_Entry sgl[TWE_MAX_ATA_SGL_LENGTH];
+} TWE_Command_ATA __attribute__ ((packed));
+
+typedef struct
+{
+ u_int8_t opcode:5;
+ u_int8_t sgl_offset:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
u_int8_t flags;
#define TWE_FLAGS_SUCCESS 0x00
#define TWE_FLAGS_INFORMATIONAL 0x01
@@ -290,6 +318,7 @@ typedef union
TWE_Command_CHECKSTATUS checkstatus;
TWE_Command_REBUILDUNIT rebuildunit;
TWE_Command_SETATAFEATURE setatafeature;
+ TWE_Command_ATA ata;
TWE_Command_Generic generic;
u_int8_t pad[512];
} TWE_Command;
@@ -460,3 +489,4 @@ typedef struct
u_int8_t parameter_size_bytes;
u_int8_t data[0];
} TWE_Param __attribute__ ((packed));
+
diff --git a/sys/dev/twe/twevar.h b/sys/dev/twe/twevar.h
index 84d41dd..3c0d6b3 100644
--- a/sys/dev/twe/twevar.h
+++ b/sys/dev/twe/twevar.h
@@ -145,6 +145,8 @@ extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller
extern void twe_attach_drive(struct twe_softc *sc,
struct twe_drive *dr); /* attach drive when found in twe_init */
+extern void twe_clear_pci_parity_error(struct twe_softc *sc);
+extern void twe_clear_pci_abort(struct twe_softc *sc);
extern void twed_intr(twe_bio *bp); /* return bio from core */
extern struct twe_request *twe_allocate_request(struct twe_softc *sc); /* allocate request structure */
extern void twe_free_request(struct twe_request *tr); /* free request structure */
OpenPOWER on IntegriCloud