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)
|
twe_setup(struct twe_softc *sc)
|
||||||
{
|
{
|
||||||
struct twe_request *tr;
|
struct twe_request *tr;
|
||||||
|
u_int32_t status_reg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
debug_called(4);
|
debug_called(4);
|
||||||
@ -148,6 +149,12 @@ twe_setup(struct twe_softc *sc)
|
|||||||
twe_release_request(tr);
|
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.
|
* Wait for the controller to come ready.
|
||||||
*/
|
*/
|
||||||
@ -566,6 +573,8 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
|
|||||||
twe_reset(sc);
|
twe_reset(sc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* XXX implement ATA PASSTHROUGH */
|
||||||
|
|
||||||
/* nothing we understand */
|
/* nothing we understand */
|
||||||
default:
|
default:
|
||||||
error = ENOTTY;
|
error = ENOTTY;
|
||||||
@ -919,12 +928,16 @@ twe_reset(struct twe_softc *sc)
|
|||||||
struct twe_request *tr;
|
struct twe_request *tr;
|
||||||
int i, s;
|
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
|
* Disable interrupts from the controller, and mask any accidental entry
|
||||||
* into our interrupt handler.
|
* into our interrupt handler.
|
||||||
*/
|
*/
|
||||||
|
twe_printf(sc, "controller reset in progress...\n");
|
||||||
twe_disable_interrupts(sc);
|
twe_disable_interrupts(sc);
|
||||||
s = splbio();
|
s = splbio();
|
||||||
|
|
||||||
@ -1178,10 +1191,11 @@ twe_soft_reset(struct twe_softc *sc)
|
|||||||
|
|
||||||
TWE_SOFT_RESET(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");
|
twe_printf(sc, "no attention interrupt\n");
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT);
|
||||||
if (twe_drain_aen_queue(sc)) {
|
if (twe_drain_aen_queue(sc)) {
|
||||||
twe_printf(sc, "can't drain AEN queue\n");
|
twe_printf(sc, "can't drain AEN queue\n");
|
||||||
return(1);
|
return(1);
|
||||||
@ -1586,6 +1600,14 @@ twe_check_bits(struct twe_softc *sc, u_int32_t status_reg)
|
|||||||
lastwarn[1] = time_second;
|
lastwarn[1] = time_second;
|
||||||
}
|
}
|
||||||
result = 1;
|
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);
|
return(result);
|
||||||
@ -1616,7 +1638,7 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen)
|
|||||||
if (!bootverbose)
|
if (!bootverbose)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 'p':
|
case 'a':
|
||||||
return(msg);
|
return(msg);
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
@ -1628,6 +1650,12 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen)
|
|||||||
}
|
}
|
||||||
return(buf);
|
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':
|
case 'x':
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1660,25 +1688,41 @@ twe_report_request(struct twe_request *tr)
|
|||||||
} else if (cmd->generic.status > TWE_STATUS_FATAL) {
|
} else if (cmd->generic.status > TWE_STATUS_FATAL) {
|
||||||
/*
|
/*
|
||||||
* Fatal errors that don't require controller reset.
|
* 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",
|
switch (cmd->generic.flags) {
|
||||||
twe_describe_code(twe_table_status, cmd->generic.status),
|
case 0x1b:
|
||||||
cmd->generic.flags);
|
device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
|
||||||
result = 1;
|
"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) {
|
} else if (cmd->generic.status > TWE_STATUS_WARNING) {
|
||||||
/*
|
/*
|
||||||
* Warning level status.
|
* Warning level status.
|
||||||
*/
|
*/
|
||||||
twe_printf(sc, "command returned warning status - %s (flags = 0x%x)\n",
|
device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
|
||||||
twe_describe_code(twe_table_status, cmd->generic.status),
|
"warning - %s (flags = 0x%x)\n",
|
||||||
cmd->generic.flags);
|
twe_describe_code(twe_table_status, cmd->generic.status),
|
||||||
|
cmd->generic.flags);
|
||||||
} else if (cmd->generic.status > 0x40) {
|
} else if (cmd->generic.status > 0x40) {
|
||||||
/*
|
/*
|
||||||
* Info level status.
|
* Info level status.
|
||||||
*/
|
*/
|
||||||
twe_printf(sc, "command returned info status: %s (flags = 0x%x)\n",
|
device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
|
||||||
twe_describe_code(twe_table_status, cmd->generic.status),
|
"attention - %s (flags = 0x%x)\n",
|
||||||
cmd->generic.flags);
|
twe_describe_code(twe_table_status, cmd->generic.status),
|
||||||
|
cmd->generic.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -90,7 +90,7 @@ static struct cdevsw twe_cdevsw = {
|
|||||||
* Accept an open operation on the control device.
|
* Accept an open operation on the control device.
|
||||||
*/
|
*/
|
||||||
static int
|
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);
|
int unit = minor(dev);
|
||||||
struct twe_softc *sc = devclass_get_softc(twe_devclass, unit);
|
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.
|
* Accept the last close on the control device.
|
||||||
*/
|
*/
|
||||||
static int
|
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);
|
int unit = minor(dev);
|
||||||
struct twe_softc *sc = devclass_get_softc(twe_devclass, unit);
|
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.
|
* Handle controller-specific control operations.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
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);
|
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
|
Disk device
|
||||||
@ -599,7 +619,7 @@ static int disks_registered = 0;
|
|||||||
* for opens on subdevices (eg. slices, partitions).
|
* for opens on subdevices (eg. slices, partitions).
|
||||||
*/
|
*/
|
||||||
static int
|
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 twed_softc *sc = (struct twed_softc *)dev->si_drv1;
|
||||||
struct disklabel *label;
|
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.
|
* Handle last close of the disk device.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
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 queue empty", 0x00},
|
||||||
{"q soft reset", 0x01},
|
{"q soft reset", 0x01},
|
||||||
{"c degraded mirror", 0x02},
|
{"c degraded mirror", 0x02},
|
||||||
{"p controller error", 0x03},
|
{"a controller error", 0x03},
|
||||||
{"c rebuild fail", 0x04},
|
{"c rebuild fail", 0x04},
|
||||||
{"c rebuild done", 0x05},
|
{"c rebuild done", 0x05},
|
||||||
{"c incomplete unit", 0x06},
|
{"c incomplete unit", 0x06},
|
||||||
@ -127,7 +127,23 @@ struct twe_code_lookup twe_table_aen[] = {
|
|||||||
{"c drive timeout", 0x09},
|
{"c drive timeout", 0x09},
|
||||||
{"c drive error", 0x0a},
|
{"c drive error", 0x0a},
|
||||||
{"c rebuild started", 0x0b},
|
{"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},
|
{NULL, 0},
|
||||||
{"x unknown AEN", 0}
|
{"x unknown AEN", 0}
|
||||||
};
|
};
|
||||||
|
@ -47,6 +47,8 @@
|
|||||||
#define TWE_CONTROL_ENABLE_INTERRUPTS 0x00000080
|
#define TWE_CONTROL_ENABLE_INTERRUPTS 0x00000080
|
||||||
#define TWE_CONTROL_DISABLE_INTERRUPTS 0x00000040
|
#define TWE_CONTROL_DISABLE_INTERRUPTS 0x00000040
|
||||||
#define TWE_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
|
#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 | \
|
#define TWE_SOFT_RESET(sc) TWE_CONTROL(sc, TWE_CONTROL_ISSUE_SOFT_RESET | \
|
||||||
TWE_CONTROL_CLEAR_HOST_INTERRUPT | \
|
TWE_CONTROL_CLEAR_HOST_INTERRUPT | \
|
||||||
@ -100,6 +102,8 @@
|
|||||||
#define TWE_VENDOR_ID 0x13C1
|
#define TWE_VENDOR_ID 0x13C1
|
||||||
#define TWE_DEVICE_ID 0x1000
|
#define TWE_DEVICE_ID 0x1000
|
||||||
#define TWE_DEVICE_ID_ASIC 0x1001
|
#define TWE_DEVICE_ID_ASIC 0x1001
|
||||||
|
#define TWE_PCI_CLEAR_PARITY_ERROR 0xc100
|
||||||
|
#define TWE_PCI_CLEAR_PCI_ABORT 0x2000
|
||||||
|
|
||||||
/* command packet opcodes */
|
/* command packet opcodes */
|
||||||
#define TWE_OP_NOP 0x00
|
#define TWE_OP_NOP 0x00
|
||||||
@ -123,6 +127,8 @@
|
|||||||
#define TWE_OP_SECTOR_INFO 0x1a
|
#define TWE_OP_SECTOR_INFO 0x1a
|
||||||
#define TWE_OP_AEN_LISTEN 0x1c
|
#define TWE_OP_AEN_LISTEN 0x1c
|
||||||
#define TWE_OP_CMD_PACKET 0x1d
|
#define TWE_OP_CMD_PACKET 0x1d
|
||||||
|
#define TWE_OP_ATA_PASSTHROUGH 0x1e
|
||||||
|
#define TWE_OP_CMD_WITH_DATA 0x1f
|
||||||
|
|
||||||
/* command status values */
|
/* command status values */
|
||||||
#define TWE_STATUS_RESET 0xff /* controller requests reset */
|
#define TWE_STATUS_RESET 0xff /* controller requests reset */
|
||||||
@ -138,6 +144,8 @@
|
|||||||
#define TWE_SHUTDOWN_MESSAGE_CREDITS 0x001
|
#define TWE_SHUTDOWN_MESSAGE_CREDITS 0x001
|
||||||
#define TWE_INIT_COMMAND_PACKET_SIZE 0x3
|
#define TWE_INIT_COMMAND_PACKET_SIZE 0x3
|
||||||
#define TWE_MAX_SGL_LENGTH 62
|
#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_LENGTH TWE_INIT_MESSAGE_CREDITS
|
||||||
#define TWE_Q_START 0
|
#define TWE_Q_START 0
|
||||||
#define TWE_MAX_RESET_TRIES 3
|
#define TWE_MAX_RESET_TRIES 3
|
||||||
@ -263,6 +271,26 @@ typedef struct
|
|||||||
u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */
|
u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */
|
||||||
} TWE_Command_REBUILDUNIT __attribute__ ((packed));
|
} 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
|
typedef struct
|
||||||
{
|
{
|
||||||
u_int8_t opcode:5;
|
u_int8_t opcode:5;
|
||||||
@ -290,6 +318,7 @@ typedef union
|
|||||||
TWE_Command_CHECKSTATUS checkstatus;
|
TWE_Command_CHECKSTATUS checkstatus;
|
||||||
TWE_Command_REBUILDUNIT rebuildunit;
|
TWE_Command_REBUILDUNIT rebuildunit;
|
||||||
TWE_Command_SETATAFEATURE setatafeature;
|
TWE_Command_SETATAFEATURE setatafeature;
|
||||||
|
TWE_Command_ATA ata;
|
||||||
TWE_Command_Generic generic;
|
TWE_Command_Generic generic;
|
||||||
u_int8_t pad[512];
|
u_int8_t pad[512];
|
||||||
} TWE_Command;
|
} TWE_Command;
|
||||||
@ -460,3 +489,4 @@ typedef struct
|
|||||||
u_int8_t parameter_size_bytes;
|
u_int8_t parameter_size_bytes;
|
||||||
u_int8_t data[0];
|
u_int8_t data[0];
|
||||||
} TWE_Param __attribute__ ((packed));
|
} 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,
|
extern void twe_attach_drive(struct twe_softc *sc,
|
||||||
struct twe_drive *dr); /* attach drive when found in twe_init */
|
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 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 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 */
|
extern void twe_free_request(struct twe_request *tr); /* free request structure */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user