Update for the 6.9 firmware family (6xxx controllers), as well as for
the upcoming 7.4 family (7xxx controllers). - improved error reporting and handling - more diagnostic output - add extra command packet definitions - merge sources again with -stable
This commit is contained in:
parent
a268f9dbeb
commit
3f1166f04c
@ -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);
|
||||
@ -148,6 +149,12 @@ twe_setup(struct twe_softc *sc)
|
||||
twe_release_request(tr);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
@ -512,6 +512,26 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
|
||||
twe_printf(sc, "bus_generic_attach returned %d\n", error);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* 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;
|
||||
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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
|
||||
@ -263,6 +271,26 @@ typedef struct
|
||||
u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */
|
||||
} TWE_Command_REBUILDUNIT __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_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;
|
||||
@ -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));
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user