After extensive QA cycles at 3ware, bring the driver in-line with all the
issues which they found and asked to be changed so 3ware can offcially support the driver. Summary of the most significant changes: - TWE_OVERRIDE is no longer supported - If twe_getparam failed, bogus data would be returned to the caller - Cache the device unit in the twe_drive structure to aid debugging - Add the 3ware driver version. - Proper return error codes for many functions. - Track the minimum queue length statistics - 4.x compat: use the cached unit number from the twe_drive structure instead of the the cached si_drv2. 3ware found that after many loads and unloads that si_drv2 became corrupted. This did not happen in -current. Submitted by: Vinod Kashyap (with modifications by me) Approved by: re (rwatson)
This commit is contained in:
parent
71e5b4d590
commit
a85e26c4bf
@ -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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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,10 +1616,25 @@ 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.
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
@ -56,43 +58,9 @@
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
/*
|
||||
* These macros allows us to build a version of the driver which can
|
||||
* safely be loaded into a kernel which already contains a 'twe' driver,
|
||||
* and which will override it in all things.
|
||||
*
|
||||
* All public symbols must be listed here.
|
||||
*/
|
||||
#ifdef TWE_OVERRIDE
|
||||
#define twe_setup Xtwe_setup
|
||||
#define twe_init Xtwe_init
|
||||
#define twe_deinit Xtwe_deinit
|
||||
#define twe_intr Xtwe_intr
|
||||
#define twe_submit_bio Xtwe_submit_bio
|
||||
#define twe_ioctl Xtwe_ioctl
|
||||
#define twe_describe_controller Xtwe_describe_controller
|
||||
#define twe_print_controller Xtwe_print_controller
|
||||
#define twe_enable_interrupts Xtwe_enable_interrupts
|
||||
#define twe_disable_interrupts Xtwe_disable_interrupts
|
||||
#define twe_attach_drive Xtwe_attach_drive
|
||||
#define twed_intr Xtwed_intr
|
||||
#define twe_allocate_request Xtwe_allocate_request
|
||||
#define twe_free_request Xtwe_free_request
|
||||
#define twe_map_request Xtwe_map_request
|
||||
#define twe_unmap_request Xtwe_unmap_request
|
||||
#define twe_describe_code Xtwe_describe_code
|
||||
#define twe_table_status Xtwe_table_status
|
||||
#define twe_table_unitstate Xtwe_table_unitstate
|
||||
#define twe_table_unittype Xtwe_table_unittype
|
||||
#define twe_table_aen Xtwe_table_aen
|
||||
#define TWE_DRIVER_NAME Xtwe
|
||||
#define TWED_DRIVER_NAME Xtwed
|
||||
#define TWE_MALLOC_CLASS M_XTWE
|
||||
#else
|
||||
#define TWE_DRIVER_NAME twe
|
||||
#define TWED_DRIVER_NAME twed
|
||||
#define TWE_MALLOC_CLASS M_TWE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wrappers for bus-space actions
|
||||
@ -142,6 +110,7 @@
|
||||
#if __FreeBSD_version < 500003
|
||||
# include <machine/clock.h>
|
||||
# define INTR_ENTROPY 0
|
||||
# define FREEBSD_4
|
||||
|
||||
# include <sys/buf.h> /* old buf style */
|
||||
typedef struct buf twe_bio;
|
||||
@ -164,6 +133,7 @@ typedef struct buf_queue_head twe_bioq;
|
||||
# define TWE_BIO_STATS_END(bp) devstat_end_transaction_buf(&((struct twed_softc *)TWE_BIO_SOFTC(bp))->twed_stats, bp)
|
||||
#else
|
||||
# include <sys/bio.h>
|
||||
# include <geom/geom_disk.h>
|
||||
typedef struct bio twe_bio;
|
||||
typedef struct bio_queue_head twe_bioq;
|
||||
# define TWE_BIO_QINIT(bq) bioq_init(&bq);
|
||||
|
@ -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.
|
||||
*
|
||||
@ -31,20 +33,14 @@
|
||||
* 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 <geom/geom_disk.h>
|
||||
#include <dev/twe/twereg.h>
|
||||
#include <dev/twe/tweio.h>
|
||||
#include <dev/twe/twevar.h>
|
||||
#include <dev/twe/twe_tables.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
static devclass_t twe_devclass;
|
||||
|
||||
#ifdef TWE_DEBUG
|
||||
@ -70,8 +66,6 @@ static d_open_t twe_open;
|
||||
static d_close_t twe_close;
|
||||
static d_ioctl_t twe_ioctl_wrapper;
|
||||
|
||||
#define TWE_CDEV_MAJOR 146
|
||||
|
||||
static struct cdevsw twe_cdevsw = {
|
||||
.d_open = twe_open,
|
||||
.d_close = twe_close,
|
||||
@ -127,7 +121,7 @@ static int twe_probe(device_t dev);
|
||||
static int twe_attach(device_t dev);
|
||||
static void twe_free(struct twe_softc *sc);
|
||||
static int twe_detach(device_t dev);
|
||||
static void twe_shutdown(device_t dev);
|
||||
static int twe_shutdown(device_t dev);
|
||||
static int twe_suspend(device_t dev);
|
||||
static int twe_resume(device_t dev);
|
||||
static void twe_pci_intr(void *arg);
|
||||
@ -153,11 +147,7 @@ static driver_t twe_pci_driver = {
|
||||
sizeof(struct twe_softc)
|
||||
};
|
||||
|
||||
#ifdef TWE_OVERRIDE
|
||||
DRIVER_MODULE(Xtwe, pci, twe_pci_driver, twe_devclass, 0, 0);
|
||||
#else
|
||||
DRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0);
|
||||
#endif
|
||||
|
||||
/********************************************************************************
|
||||
* Match a 3ware Escalade ATA RAID controller.
|
||||
@ -171,12 +161,8 @@ twe_probe(device_t dev)
|
||||
if ((pci_get_vendor(dev) == TWE_VENDOR_ID) &&
|
||||
((pci_get_device(dev) == TWE_DEVICE_ID) ||
|
||||
(pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) {
|
||||
device_set_desc(dev, TWE_DEVICE_NAME);
|
||||
#ifdef TWE_OVERRIDE
|
||||
device_set_desc_copy(dev, TWE_DEVICE_NAME ". Driver version " TWE_DRIVER_VERSION_STRING);
|
||||
return(0);
|
||||
#else
|
||||
return(-10);
|
||||
#endif
|
||||
}
|
||||
return(ENXIO);
|
||||
}
|
||||
@ -208,7 +194,7 @@ twe_attach(device_t dev)
|
||||
return (ENXIO);
|
||||
}
|
||||
SYSCTL_ADD_STRING(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
|
||||
OID_AUTO, "driver_version", CTLFLAG_RD, "$Revision$", 0,
|
||||
OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0,
|
||||
"TWE driver version");
|
||||
|
||||
/*
|
||||
@ -459,7 +445,8 @@ twe_detach(device_t dev)
|
||||
/*
|
||||
* Shut the controller down.
|
||||
*/
|
||||
twe_shutdown(dev);
|
||||
if (twe_shutdown(dev))
|
||||
goto out;
|
||||
|
||||
twe_free(sc);
|
||||
|
||||
@ -475,11 +462,11 @@ twe_detach(device_t dev)
|
||||
* Note that we can assume that the bioq on the controller is empty, as we won't
|
||||
* allow shutdown if any device is open.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
twe_shutdown(device_t dev)
|
||||
{
|
||||
struct twe_softc *sc = device_get_softc(dev);
|
||||
int i, s;
|
||||
int i, s, error = 0;
|
||||
|
||||
debug_called(4);
|
||||
|
||||
@ -489,7 +476,10 @@ twe_shutdown(device_t dev)
|
||||
* Delete all our child devices.
|
||||
*/
|
||||
for (i = 0; i < TWE_MAX_UNITS; i++) {
|
||||
twe_detach_drive(sc, i);
|
||||
if (sc->twe_drive[i].td_disk != 0) {
|
||||
if ((error = twe_detach_drive(sc, i)) != 0)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -497,7 +487,9 @@ twe_shutdown(device_t dev)
|
||||
*/
|
||||
twe_deinit(sc);
|
||||
|
||||
out:
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -564,9 +556,9 @@ twe_intrhook(void *arg)
|
||||
/********************************************************************************
|
||||
* Given a detected drive, attach it to the bio interface.
|
||||
*
|
||||
* This is called from twe_init.
|
||||
* This is called from twe_add_unit.
|
||||
*/
|
||||
void
|
||||
int
|
||||
twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
|
||||
{
|
||||
char buf[80];
|
||||
@ -574,8 +566,8 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
|
||||
|
||||
dr->td_disk = device_add_child(sc->twe_dev, NULL, -1);
|
||||
if (dr->td_disk == NULL) {
|
||||
twe_printf(sc, "device_add_child failed\n");
|
||||
return;
|
||||
twe_printf(sc, "Cannot add unit\n");
|
||||
return (EIO);
|
||||
}
|
||||
device_set_ivars(dr->td_disk, dr);
|
||||
|
||||
@ -584,13 +576,16 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
|
||||
* always set...
|
||||
*/
|
||||
sprintf(buf, "Unit %d, %s, %s",
|
||||
dr->td_unit,
|
||||
dr->td_twe_unit,
|
||||
twe_describe_code(twe_table_unittype, dr->td_type),
|
||||
twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK));
|
||||
device_set_desc_copy(dr->td_disk, buf);
|
||||
|
||||
if ((error = bus_generic_attach(sc->twe_dev)) != 0)
|
||||
twe_printf(sc, "bus_generic_attach returned %d\n", error);
|
||||
if ((error = bus_generic_attach(sc->twe_dev)) != 0) {
|
||||
twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error);
|
||||
return (EIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -598,15 +593,17 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
|
||||
*
|
||||
* This is called from twe_del_unit.
|
||||
*/
|
||||
void
|
||||
int
|
||||
twe_detach_drive(struct twe_softc *sc, int unit)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (sc->twe_drive[unit].td_disk != 0) {
|
||||
if (device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk) != 0)
|
||||
twe_printf(sc, "failed to delete unit %d\n", unit);
|
||||
sc->twe_drive[unit].td_disk = 0;
|
||||
if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk)) != 0) {
|
||||
twe_printf(sc, "failed to delete unit %d\n", unit);
|
||||
return(error);
|
||||
}
|
||||
bzero(&sc->twe_drive[unit], sizeof(sc->twe_drive[unit]));
|
||||
return(error);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -638,7 +635,7 @@ twe_clear_pci_abort(struct twe_softc *sc)
|
||||
/*
|
||||
* Disk device softc
|
||||
*/
|
||||
struct twed_softc
|
||||
struct twed_softc
|
||||
{
|
||||
device_t twed_dev;
|
||||
struct twe_softc *twed_controller; /* parent device softc */
|
||||
@ -667,11 +664,7 @@ static driver_t twed_driver = {
|
||||
};
|
||||
|
||||
static devclass_t twed_devclass;
|
||||
#ifdef TWE_OVERRIDE
|
||||
DRIVER_MODULE(Xtwed, Xtwe, twed_driver, twed_devclass, 0, 0);
|
||||
#else
|
||||
DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Disk device control interface.
|
||||
@ -714,11 +707,11 @@ twed_strategy(twe_bio *bp)
|
||||
|
||||
debug_called(4);
|
||||
|
||||
bp->bio_driver1 = &sc->twed_drive->td_unit;
|
||||
bp->bio_driver1 = &sc->twed_drive->td_twe_unit;
|
||||
TWED_BIO_IN;
|
||||
|
||||
/* bogus disk? */
|
||||
if (sc == NULL) {
|
||||
if (sc == NULL || sc->twed_drive->td_disk == NULL) {
|
||||
TWE_BIO_SET_ERROR(bp, EINVAL);
|
||||
printf("twe: bio for invalid disk!\n");
|
||||
TWE_BIO_DONE(bp);
|
||||
@ -755,7 +748,7 @@ twed_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t l
|
||||
return(ENXIO);
|
||||
|
||||
if (length > 0) {
|
||||
if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_unit, offset / TWE_BLOCK_SIZE, virtual, length / TWE_BLOCK_SIZE)) != 0)
|
||||
if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, offset / TWE_BLOCK_SIZE, virtual, length / TWE_BLOCK_SIZE)) != 0)
|
||||
return(error);
|
||||
}
|
||||
return(0);
|
||||
@ -822,8 +815,9 @@ twed_attach(device_t dev)
|
||||
sc->twed_disk.d_mediasize = TWE_BLOCK_SIZE * (off_t)sc->twed_drive->td_size;
|
||||
sc->twed_disk.d_fwsectors = sc->twed_drive->td_sectors;
|
||||
sc->twed_disk.d_fwheads = sc->twed_drive->td_heads;
|
||||
sc->twed_drive->td_sys_unit = device_get_unit(dev);
|
||||
|
||||
disk_create(device_get_unit(dev), &sc->twed_disk, 0, NULL, NULL);
|
||||
disk_create(sc->twed_drive->td_sys_unit, &sc->twed_disk, 0, NULL, NULL);
|
||||
#ifdef FREEBSD_4
|
||||
disks_registered++;
|
||||
#endif
|
||||
@ -846,13 +840,12 @@ twed_detach(device_t dev)
|
||||
if (sc->twed_disk.d_flags & DISKFLAG_OPEN)
|
||||
return(EBUSY);
|
||||
|
||||
disk_destroy(&sc->twed_disk);
|
||||
|
||||
#ifdef FREEBSD_4
|
||||
if (--disks_registered == 0)
|
||||
cdevsw_remove(&tweddisk_cdevsw);
|
||||
#else
|
||||
disk_destroy(&sc->twed_disk);
|
||||
#endif
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
@ -45,21 +47,6 @@ extern struct twe_code_lookup twe_table_aen[];
|
||||
extern struct twe_code_lookup twe_table_opcode[];
|
||||
#else /* TWE_DEFINE_TABLES */
|
||||
|
||||
/********************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
struct twe_code_lookup twe_table_status[] = {
|
||||
/* success */
|
||||
{"successful completion", 0x00},
|
||||
@ -117,7 +104,7 @@ struct twe_code_lookup twe_table_unittype[] = {
|
||||
struct twe_code_lookup twe_table_aen[] = {
|
||||
{"q queue empty", 0x00},
|
||||
{"q soft reset", 0x01},
|
||||
{"c degraded mirror", 0x02},
|
||||
{"c degraded unit", 0x02},
|
||||
{"a controller error", 0x03},
|
||||
{"c rebuild fail", 0x04},
|
||||
{"c rebuild done", 0x05},
|
||||
|
@ -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.
|
||||
*
|
||||
@ -55,6 +57,7 @@ struct twe_usercommand {
|
||||
struct twe_qstat {
|
||||
u_int32_t q_length;
|
||||
u_int32_t q_max;
|
||||
u_int32_t q_min;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -70,8 +73,8 @@ union twe_statrequest {
|
||||
/*
|
||||
* AEN listen
|
||||
*/
|
||||
#define TWEIO_AEN_POLL _IOR('T', 102, int)
|
||||
#define TWEIO_AEN_WAIT _IOR('T', 103, int)
|
||||
#define TWEIO_AEN_POLL _IOR('T', 102, u_int16_t)
|
||||
#define TWEIO_AEN_WAIT _IOR('T', 103, u_int16_t)
|
||||
|
||||
/*
|
||||
* Controller parameter access
|
||||
|
@ -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.
|
||||
*
|
||||
@ -98,7 +100,7 @@
|
||||
|
||||
/* PCI related defines */
|
||||
#define TWE_IO_CONFIG_REG 0x10
|
||||
#define TWE_DEVICE_NAME "3ware Storage Controller"
|
||||
#define TWE_DEVICE_NAME "3ware 7000 series Storage Controller"
|
||||
#define TWE_VENDOR_ID 0x13C1
|
||||
#define TWE_DEVICE_ID 0x1000
|
||||
#define TWE_DEVICE_ID_ASIC 0x1001
|
||||
@ -280,6 +282,7 @@ typedef struct
|
||||
u_int8_t unit:4;
|
||||
u_int8_t host_id:4;
|
||||
u_int8_t status;
|
||||
u_int8_t flags;
|
||||
u_int16_t param;
|
||||
u_int16_t features;
|
||||
u_int16_t sector_count;
|
||||
|
@ -27,6 +27,14 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* The scheme for the driver version is:
|
||||
* <major change>.<external release>.<3ware internal release>.<development release>
|
||||
*/
|
||||
#define TWE_DRIVER_VERSION_STRING "1.50.00.000"
|
||||
#define TWE_CDEV_MAJOR 146
|
||||
#define TWED_CDEV_MAJOR 147
|
||||
|
||||
#ifdef TWE_DEBUG
|
||||
#define debug(level, fmt, args...) \
|
||||
do { \
|
||||
@ -51,7 +59,8 @@ struct twe_drive
|
||||
int td_cylinders;
|
||||
int td_heads;
|
||||
int td_sectors;
|
||||
int td_unit;
|
||||
int td_sys_unit; /* device unit number */
|
||||
int td_twe_unit; /* index into sc->twe_drive[] */
|
||||
|
||||
/* unit state and type */
|
||||
u_int8_t td_state;
|
||||
@ -151,9 +160,9 @@ extern void twe_print_controller(struct twe_softc *sc);
|
||||
extern void twe_enable_interrupts(struct twe_softc *sc); /* enable controller interrupts */
|
||||
extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller interrupts */
|
||||
|
||||
extern void twe_attach_drive(struct twe_softc *sc,
|
||||
extern int twe_attach_drive(struct twe_softc *sc,
|
||||
struct twe_drive *dr); /* attach drive when found in twe_init */
|
||||
extern void twe_detach_drive(struct twe_softc *sc,
|
||||
extern int twe_detach_drive(struct twe_softc *sc,
|
||||
int unit); /* detach drive */
|
||||
extern void twe_clear_pci_parity_error(struct twe_softc *sc);
|
||||
extern void twe_clear_pci_abort(struct twe_softc *sc);
|
||||
@ -175,11 +184,20 @@ 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) \
|
||||
do { \
|
||||
sc->twe_qstat[qname].q_length = 0; \
|
||||
sc->twe_qstat[qname].q_max = 0; \
|
||||
#define TWEQ_REMOVE(sc, qname) \
|
||||
do { \
|
||||
struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \
|
||||
\
|
||||
qs->q_length--; \
|
||||
if (qs->q_length < qs->q_min) \
|
||||
qs->q_min = qs->q_length; \
|
||||
} while(0);
|
||||
|
||||
#define TWEQ_INIT(sc, qname) \
|
||||
do { \
|
||||
sc->twe_qstat[qname].q_length = 0; \
|
||||
sc->twe_qstat[qname].q_max = 0; \
|
||||
sc->twe_qstat[qname].q_min = 0xFFFFFFFF; \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user