diff options
author | ps <ps@FreeBSD.org> | 2003-12-02 07:57:20 +0000 |
---|---|---|
committer | ps <ps@FreeBSD.org> | 2003-12-02 07:57:20 +0000 |
commit | 3a0af1aae72ca3322637a9d2f7f8b765835748c7 (patch) | |
tree | ba946a6caff762ad522eba49b289c9bb061bd1d4 /sys/dev/twe | |
parent | 61573506be17296e8a4f3b70686c75fb30900e65 (diff) | |
download | FreeBSD-src-3a0af1aae72ca3322637a9d2f7f8b765835748c7.zip FreeBSD-src-3a0af1aae72ca3322637a9d2f7f8b765835748c7.tar.gz |
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)
Diffstat (limited to 'sys/dev/twe')
-rw-r--r-- | sys/dev/twe/twe.c | 148 | ||||
-rw-r--r-- | sys/dev/twe/twe_compat.h | 38 | ||||
-rw-r--r-- | sys/dev/twe/twe_freebsd.c | 91 | ||||
-rw-r--r-- | sys/dev/twe/twe_tables.h | 19 | ||||
-rw-r--r-- | sys/dev/twe/tweio.h | 7 | ||||
-rw-r--r-- | sys/dev/twe/twereg.h | 5 | ||||
-rw-r--r-- | sys/dev/twe/twevar.h | 34 |
7 files changed, 184 insertions, 158 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); } diff --git a/sys/dev/twe/twe_compat.h b/sys/dev/twe/twe_compat.h index 981199a..78922a6 100644 --- a/sys/dev/twe/twe_compat.h +++ b/sys/dev/twe/twe_compat.h @@ -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); diff --git a/sys/dev/twe/twe_freebsd.c b/sys/dev/twe/twe_freebsd.c index c7c313f..34e4954 100644 --- a/sys/dev/twe/twe_freebsd.c +++ b/sys/dev/twe/twe_freebsd.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. * @@ -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); } diff --git a/sys/dev/twe/twe_tables.h b/sys/dev/twe/twe_tables.h index 4c0d719..3ba83c9 100644 --- a/sys/dev/twe/twe_tables.h +++ b/sys/dev/twe/twe_tables.h @@ -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}, diff --git a/sys/dev/twe/tweio.h b/sys/dev/twe/tweio.h index 7aed7d1..1b78472 100644 --- a/sys/dev/twe/tweio.h +++ b/sys/dev/twe/tweio.h @@ -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 diff --git a/sys/dev/twe/twereg.h b/sys/dev/twe/twereg.h index 705f419..5737b82 100644 --- a/sys/dev/twe/twereg.h +++ b/sys/dev/twe/twereg.h @@ -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; diff --git a/sys/dev/twe/twevar.h b/sys/dev/twe/twevar.h index 22fb966..63700da 100644 --- a/sys/dev/twe/twevar.h +++ b/sys/dev/twe/twevar.h @@ -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) |