From: Sascha Wildner Date: Fri, 3 Dec 2010 13:34:47 +0000 (+0100) Subject: amr(4): Sync with FreeBSD. X-Git-Tag: v2.11.0~527 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/1fcd0ba2bee231ffad374d52197e61fecd6cef32 amr(4): Sync with FreeBSD. This adds support for various new devices (full list is in the manual page), among other things. Reported-by: Tomaz Borstnar Jonas Trollvik Dragonfly-bug: --- diff --git a/share/man/man4/amr.4 b/share/man/man4/amr.4 index a0eb9f34ce..000be24aff 100644 --- a/share/man/man4/amr.4 +++ b/share/man/man4/amr.4 @@ -21,37 +21,86 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/share/man/man4/amr.4,v 1.3.2.10 2003/05/26 12:41:05 hmp Exp $ +.\" $FreeBSD: src/share/man/man4/amr.4,v 1.35 2006/06/18 14:45:28 brueffer Exp $ .\" -.Dd November 30, 2010 +.Dd December 3, 2010 .Dt AMR 4 .Os .Sh NAME .Nm amr -.Nd AMI MegaRAID PCI-SCSI RAID driver +.Nd MegaRAID SCSI/ATA/SATA RAID driver .Sh SYNOPSIS -.Cd device pci -.Cd device amr +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device pci" +.Cd "device scbus" +.Cd "device amr" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +amr_load="YES" +.Ed .Sh DESCRIPTION The .Nm -driver provides support for American Megatrends MegaRAID Express, -Elite and Enterprise family SCSI RAID controllers, -including models relabeled and sold by Hewlett-Packard and Dell. +driver provides support for LSI Logic MegaRAID SCSI, ATA and SATA +RAID controllers and legacy American Megatrends MegaRAID +SCSI RAID controllers, including models relabeled +and sold by Dell and Hewlett-Packard. .Pp LSI MegaRAID SAS controllers are supported by .Xr mfi 4 and will not work with this driver. +.Sh HARDWARE +Controllers supported by the +.Nm +driver include: .Pp -Supported controllers include: -.Bl -bullet +.Bl -bullet -compact +.It +MegaRAID SATA 150-4 +.It +MegaRAID SATA 150-6 +.It +MegaRAID SATA 300-4X +.It +MegaRAID SATA 300-8X +.It +MegaRAID SCSI 320-1E +.It +MegaRAID SCSI 320-2E +.It +MegaRAID SCSI 320-4E .It -MegaRAID 320-1 +MegaRAID SCSI 320-0X .It -MegaRAID 320-2 +MegaRAID SCSI 320-2X +.It +MegaRAID SCSI 320-4X +.It +MegaRAID SCSI 320-0 +.It +MegaRAID SCSI 320-1 +.It +MegaRAID SCSI 320-2 +.It +MegaRAID SCSI 320-4 .It MegaRAID Series 418 .It +MegaRAID i4 133 RAID +.It +MegaRAID Elite 1500 (Series 467) +.It +MegaRAID Elite 1600 (Series 493) +.It +MegaRAID Elite 1650 (Series 4xx) +.It MegaRAID Enterprise 1200 (Series 428) .It MegaRAID Enterprise 1300 (Series 434) @@ -62,10 +111,6 @@ MegaRAID Enterprise 1500 (Series 467) .It MegaRAID Enterprise 1600 (Series 471) .It -MegaRAID Elite 1500 (Series 467) -.It -MegaRAID Elite 1600 (Series 493) -.It MegaRAID Express 100 (Series 466WS) .It MegaRAID Express 200 (Series 466) @@ -80,11 +125,35 @@ Dell PERC 2/SC .It Dell PERC 2/DC .It +Dell PERC 3/DCL +.It +Dell PERC 3/QC +.It +Dell PERC 4/DC +.It +Dell PERC 4/IM +.It +Dell PERC 4/SC +.It +Dell PERC 4/Di +.It +Dell PERC 4e/DC +.It +Dell PERC 4e/Di +.It +Dell PERC 4e/Si +.It +Dell PERC 4ei +.It HP NetRAID-1/Si .It -HP NetRAID-3/Si +HP NetRAID-3/Si (D4943A) .It HP Embedded NetRAID +.It +Intel RAID Controller SRCS16 +.It +Intel RAID Controller SRCU42X .El .Sh DIAGNOSTICS .Ss Driver initialisation/shutdown phase @@ -164,12 +233,9 @@ An I/O error has occurred. The .Nm driver was written by -.An Mike Smith -.Aq msmith@FreeBSD.org . +.An Mike Smith Aq msmith@FreeBSD.org . .Pp This manual page was written by -.An Mike Smith -.Aq msmith@FreeBSD.org +.An Mike Smith Aq msmith@FreeBSD.org and -.An Jeroen Ruigrok van der Werven -.Aq asmodai@FreeBSD.org . +.An Jeroen Ruigrok van der Werven Aq asmodai@FreeBSD.org . diff --git a/sys/conf/files b/sys/conf/files index 7917ed3027..19fbb489bb 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -193,10 +193,11 @@ dev/disk/nata/atapi-cam.c optional natapicam dev/disk/nata/atapi-cd.c optional natapicd dev/disk/nata/atapi-fd.c optional natapifd dev/disk/nata/atapi-tape.c optional natapist -dev/raid/amr/amr_cam.c optional amr -dev/raid/amr/amr_disk.c optional amr -dev/raid/amr/amr_pci.c optional amr dev/raid/amr/amr.c optional amr +dev/raid/amr/amr_cam.c optional amrp amr +dev/raid/amr/amr_disk.c optional amr +#dev/raid/amr/amr_linux.c optional amr compat_linux +dev/raid/amr/amr_pci.c optional amr pci dev/disk/aha/aha.c optional aha dev/disk/aha/aha_isa.c optional aha isa dev/disk/ahb/ahb.c optional ahb eisa diff --git a/sys/config/GENERIC b/sys/config/GENERIC index ff70cfea62..8f281c977c 100644 --- a/sys/config/GENERIC +++ b/sys/config/GENERIC @@ -167,6 +167,7 @@ device aac # Adaptec FSA RAID, Dell PERC2/PERC3 device ida # Compaq Smart RAID device ips # IBM ServeRAID device amr # AMI MegaRAID +device amrp # SCSI Passthrough interface (optional, CAM req.) device mlx # Mylex DAC960 family device mfi # LSI MegaRAID SAS device mfip # LSI MegaRAID SAS passthrough, requires CAM diff --git a/sys/config/GENERIC_SMP b/sys/config/GENERIC_SMP index b30a139787..619d777d5b 100644 --- a/sys/config/GENERIC_SMP +++ b/sys/config/GENERIC_SMP @@ -168,6 +168,7 @@ device aac # Adaptec FSA RAID, Dell PERC2/PERC3 device ida # Compaq Smart RAID device ips # IBM ServeRAID device amr # AMI MegaRAID +device amrp # SCSI Passthrough interface (optional, CAM req.) device mlx # Mylex DAC960 family device mfi # LSI MegaRAID SAS device mfip # LSI MegaRAID SAS passthrough, requires CAM diff --git a/sys/config/LINT b/sys/config/LINT index 664aa9501a..fbe6f041ab 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -1258,6 +1258,7 @@ device aacp # SCSI Passthrough interface (optional, CAM required) device ida # Compaq Smart RAID device mlx # Mylex DAC960 device amr # AMI MegaRAID +device amrp # SCSI Passthrough interface (optional, CAM req.) device mfi # LSI MegaRAID SAS device mfip # LSI MegaRAID SAS passthrough, requires CAM options MFI_DEBUG diff --git a/sys/config/X86_64_GENERIC b/sys/config/X86_64_GENERIC index dcf7f50feb..a66a733fcd 100644 --- a/sys/config/X86_64_GENERIC +++ b/sys/config/X86_64_GENERIC @@ -153,6 +153,7 @@ device aac # Adaptec FSA RAID, Dell PERC2/PERC3 device ida # Compaq Smart RAID device ips # IBM ServeRAID device amr # AMI MegaRAID +device amrp # SCSI Passthrough interface (optional, CAM req.) device mlx # Mylex DAC960 family device mfi # LSI MegaRAID SAS device mfip # LSI MegaRAID SAS passthrough, requires CAM diff --git a/sys/config/X86_64_GENERIC_SMP b/sys/config/X86_64_GENERIC_SMP index d78c013ba5..6c3ffb8741 100644 --- a/sys/config/X86_64_GENERIC_SMP +++ b/sys/config/X86_64_GENERIC_SMP @@ -153,6 +153,7 @@ device aac # Adaptec FSA RAID, Dell PERC2/PERC3 device ida # Compaq Smart RAID device ips # IBM ServeRAID device amr # AMI MegaRAID +device amrp # SCSI Passthrough interface (optional, CAM req.) device mlx # Mylex DAC960 family device mfi # LSI MegaRAID SAS device mfip # LSI MegaRAID SAS passthrough, requires CAM diff --git a/sys/dev/raid/amr/Makefile b/sys/dev/raid/amr/Makefile index 88c30c922e..802cd5e38b 100644 --- a/sys/dev/raid/amr/Makefile +++ b/sys/dev/raid/amr/Makefile @@ -1,16 +1,17 @@ -# $FreeBSD: src/sys/modules/amr/Makefile,v 1.4.2.2 2002/10/28 21:10:06 emoore Exp $ +# $FreeBSD: src/sys/modules/amr/Makefile,v 1.14 2010/08/23 06:13:29 imp Exp $ -KMOD = amr -SRCS = amr.c amr_pci.c amr_disk.c device_if.h bus_if.h pci_if.h +SUBDIR= amr_cam +#.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +#SUBDIR+= amr_linux +#.endif -# SCSI passthrough support for non-disk devices -#CFLAGS += -DAMR_SCSI_PASSTHROUGH -SRCS += amr_cam.c opt_cam.h opt_scsi.h +KMOD= amr +SRCS= amr.c amr_pci.c amr_disk.c device_if.h bus_if.h pci_if.h # Enable a questionable optimisation for newer adapters -#CFLAGS += -DAMR_QUARTZ_GOFASTER +#CFLAGS+= -DAMR_QUARTZ_GOFASTER # Debugging -#CFLAGS += -DAMR_DEBUG=3 +#CFLAGS+= -DAMR_DEBUG=3 .include diff --git a/sys/dev/raid/amr/amr.c b/sys/dev/raid/amr/amr.c index d6072767f5..d9ae28a545 100644 --- a/sys/dev/raid/amr/amr.c +++ b/sys/dev/raid/amr/amr.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 1999,2000 Michael Smith * Copyright (c) 2000 BSDi + * Copyright (c) 2005 Scott Long * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,9 +24,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + */ +/*- * Copyright (c) 2002 Eric Moore - * Copyright (c) 2002 LSI Logic Corporation + * Copyright (c) 2002, 2004 LSI Logic Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +54,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amr.c,v 1.7.2.13 2003/01/15 13:41:18 emoore Exp $ + * $FreeBSD: src/sys/dev/amr/amr.c,v 1.95 2010/01/07 21:01:37 mbr Exp $ */ /* @@ -63,23 +65,28 @@ #include #include #include +#include +#include +#include -#include "amr_compat.h" +#include #include #include -#include -#include #include + +#include #include #include #include -#include "amrio.h" -#include "amrreg.h" -#include "amrvar.h" +#include +#include +#include #define AMR_DEFINE_TABLES -#include "amr_tables.h" +#include + +SYSCTL_NODE(_hw, OID_AUTO, amr, CTLFLAG_RD, 0, "AMR driver parameters"); static d_open_t amr_open; static d_close_t amr_close; @@ -89,9 +96,10 @@ static struct dev_ops amr_ops = { { "amr", 0, 0 }, .d_open = amr_open, .d_close = amr_close, - .d_ioctl = amr_ioctl + .d_ioctl = amr_ioctl, }; +int linux_no_adapter = 0; /* * Initialisation, bus interface. */ @@ -102,7 +110,7 @@ static void amr_startup(void *arg); */ static int amr_query_controller(struct amr_softc *sc); static void *amr_enquiry(struct amr_softc *sc, size_t bufsize, - u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual); + u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual, int *status); static void amr_completeio(struct amr_command *ac); static int amr_support_ext_cdb(struct amr_softc *sc); @@ -116,12 +124,15 @@ static void amr_freecmd_cluster(struct amr_command_cluster *acc); * Command processing. */ static int amr_bio_command(struct amr_softc *sc, struct amr_command **acp); -static int amr_wait_command(struct amr_command *ac); -static int amr_getslot(struct amr_command *ac); -static void amr_mapcmd(struct amr_command *ac); +static int amr_wait_command(struct amr_command *ac) __unused; +static int amr_mapcmd(struct amr_command *ac); static void amr_unmapcmd(struct amr_command *ac); static int amr_start(struct amr_command *ac); -static void amr_complete(void *context, int pending); +static void amr_complete(void *context, ac_qhead_t *head); +static void amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_abort_load(struct amr_command *ac); /* * Status monitoring @@ -131,11 +142,12 @@ static void amr_periodic(void *data); /* * Interface-specific shims */ -static int amr_quartz_submit_command(struct amr_softc *sc); +static int amr_quartz_submit_command(struct amr_command *ac); static int amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); static int amr_quartz_poll_command(struct amr_command *ac); +static int amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac); -static int amr_std_submit_command(struct amr_softc *sc); +static int amr_std_submit_command(struct amr_command *ac); static int amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); static int amr_std_poll_command(struct amr_command *ac); static void amr_std_attach_mailbox(struct amr_softc *sc); @@ -155,7 +167,11 @@ static void amr_printcommand(struct amr_command *ac); #endif #endif -DECLARE_DUMMY_MODULE(amr); +static void amr_init_sysctl(struct amr_softc *sc); +static int amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, + int32_t flag, struct sysmsg *sm); + +MALLOC_DEFINE(M_AMR, "amr", "AMR memory"); /******************************************************************************** ******************************************************************************** @@ -175,25 +191,18 @@ DECLARE_DUMMY_MODULE(amr); int amr_attach(struct amr_softc *sc) { + device_t child; debug_called(1); /* * Initialise per-controller queues. */ - TAILQ_INIT(&sc->amr_completed); - TAILQ_INIT(&sc->amr_freecmds); + amr_init_qhead(&sc->amr_freecmds); + amr_init_qhead(&sc->amr_ready); TAILQ_INIT(&sc->amr_cmd_clusters); - TAILQ_INIT(&sc->amr_ready); bioq_init(&sc->amr_bioq); -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 - /* - * Initialise command-completion task. - */ - TASK_INIT(&sc->amr_task_complete, 0, amr_complete, sc); -#endif - debug(2, "queue init done"); /* @@ -203,6 +212,7 @@ amr_attach(struct amr_softc *sc) sc->amr_submit_command = amr_quartz_submit_command; sc->amr_get_work = amr_quartz_get_work; sc->amr_poll_command = amr_quartz_poll_command; + sc->amr_poll_command1 = amr_quartz_poll_command1; } else { sc->amr_submit_command = amr_std_submit_command; sc->amr_get_work = amr_std_get_work; @@ -211,10 +221,15 @@ amr_attach(struct amr_softc *sc) } #ifdef AMR_BOARD_INIT - if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc)))) + if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc))) return(ENXIO); #endif + /* + * Allocate initial commands. + */ + amr_alloccmd_cluster(sc); + /* * Quiz controller for features and limits. */ @@ -223,21 +238,45 @@ amr_attach(struct amr_softc *sc) debug(2, "controller query complete"); + /* + * preallocate the remaining commands. + */ + while (sc->amr_nextslot < sc->amr_maxio) + amr_alloccmd_cluster(sc); + + /* + * Setup sysctls. + */ + sysctl_ctx_init(&sc->amr_sysctl_ctx); + sc->amr_sysctl_tree = SYSCTL_ADD_NODE(&sc->amr_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, + device_get_nameunit(sc->amr_dev), CTLFLAG_RD, 0, ""); + if (sc->amr_sysctl_tree == NULL) { + device_printf(sc->amr_dev, "can't add sysctl node\n"); + return (EINVAL); + } + amr_init_sysctl(sc); + /* * Attach our 'real' SCSI channels to CAM. */ - if (amr_cam_attach(sc)) - return(ENXIO); - debug(2, "CAM attach done"); + child = device_add_child(sc->amr_dev, "amrp", -1); + sc->amr_pass = child; + if (child != NULL) { + device_set_softc(child, sc); + device_set_desc(child, "SCSI Passthrough Bus"); + bus_generic_attach(sc->amr_dev); + } /* * Create the control device. */ - sc->amr_dev_t = make_dev(&amr_ops, device_get_unit(sc->amr_dev), - UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, - "amr%d", device_get_unit(sc->amr_dev)); + sc->amr_dev_t = make_dev(&amr_ops, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR, + S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev)); sc->amr_dev_t->si_drv1 = sc; - reference_dev(sc->amr_dev_t); + linux_no_adapter++; + if (device_get_unit(sc->amr_dev) == 0) + make_dev_alias(sc->amr_dev_t, "megadev0"); /* * Schedule ourselves to bring the controller up once interrupts are @@ -246,7 +285,6 @@ amr_attach(struct amr_softc *sc) bzero(&sc->amr_ich, sizeof(struct intr_config_hook)); sc->amr_ich.ich_func = amr_startup; sc->amr_ich.ich_arg = sc; - sc->amr_ich.ich_desc = "amr"; if (config_intrhook_establish(&sc->amr_ich) != 0) { device_printf(sc->amr_dev, "can't establish configuration hook\n"); return(ENOMEM); @@ -275,7 +313,9 @@ amr_startup(void *arg) callout_init(&sc->amr_timeout); /* pull ourselves off the intrhook chain */ - config_intrhook_disestablish(&sc->amr_ich); + if (sc->amr_ich.ich_func) + config_intrhook_disestablish(&sc->amr_ich); + sc->amr_ich.ich_func = NULL; /* get up-to-date drive information */ if (amr_query_controller(sc)) { @@ -316,11 +356,34 @@ amr_startup(void *arg) /* * Start the timeout routine. */ -/* callout_reset(&sc->amr_timeout, hz, amr_periodic, sc); */ +/* sc->amr_timeout = timeout(amr_periodic, sc, hz);*/ return; } +static void +amr_init_sysctl(struct amr_softc *sc) +{ + + SYSCTL_ADD_INT(&sc->amr_sysctl_ctx, + SYSCTL_CHILDREN(sc->amr_sysctl_tree), + OID_AUTO, "allow_volume_configure", CTLFLAG_RW, &sc->amr_allow_vol_config, 0, + ""); + SYSCTL_ADD_INT(&sc->amr_sysctl_ctx, + SYSCTL_CHILDREN(sc->amr_sysctl_tree), + OID_AUTO, "nextslot", CTLFLAG_RD, &sc->amr_nextslot, 0, + ""); + SYSCTL_ADD_INT(&sc->amr_sysctl_ctx, + SYSCTL_CHILDREN(sc->amr_sysctl_tree), + OID_AUTO, "busyslots", CTLFLAG_RD, &sc->amr_busyslots, 0, + ""); + SYSCTL_ADD_INT(&sc->amr_sysctl_ctx, + SYSCTL_CHILDREN(sc->amr_sysctl_tree), + OID_AUTO, "maxio", CTLFLAG_RD, &sc->amr_maxio, 0, + ""); +} + + /******************************************************************************* * Free resources associated with a controller instance */ @@ -330,7 +393,8 @@ amr_free(struct amr_softc *sc) struct amr_command_cluster *acc; /* detach from CAM */ - amr_cam_detach(sc); + if (sc->amr_pass != NULL) + device_delete_child(sc->amr_dev, sc->amr_pass); /* cancel status timeout */ callout_stop(&sc->amr_timeout); @@ -342,9 +406,23 @@ amr_free(struct amr_softc *sc) } /* destroy control device */ - if( sc->amr_dev_t != (cdev_t)NULL) + if(sc->amr_dev_t != (struct cdev *)NULL) destroy_dev(sc->amr_dev_t); dev_ops_remove_minor(&amr_ops, device_get_unit(sc->amr_dev)); + +#if 0 /* XXX swildner */ + if (mtx_initialized(&sc->amr_hw_lock)) + mtx_destroy(&sc->amr_hw_lock); + + if (mtx_initialized(&sc->amr_list_lock)) + mtx_destroy(&sc->amr_list_lock); +#endif + + if (sc->amr_sysctl_tree != NULL) + sysctl_ctx_free(&sc->amr_sysctl_ctx); + + lockuninit(&sc->amr_hw_lock); + lockuninit(&sc->amr_list_lock); } /******************************************************************************* @@ -356,8 +434,10 @@ amr_submit_bio(struct amr_softc *sc, struct bio *bio) { debug_called(2); + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); amr_enqueue_bio(sc, bio); amr_startio(sc); + lockmgr(&sc->amr_list_lock, LK_RELEASE); return(0); } @@ -367,7 +447,7 @@ amr_submit_bio(struct amr_softc *sc, struct bio *bio) static int amr_open(struct dev_open_args *ap) { - cdev_t dev = ap->a_head.a_dev; + cdev_t dev = ap->a_head.a_dev; int unit = minor(dev); struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); @@ -377,13 +457,54 @@ amr_open(struct dev_open_args *ap) return(0); } +#ifdef LSI +static int +amr_del_ld(struct amr_softc *sc, int drv_no, int status) +{ + + debug_called(1); + + sc->amr_state &= ~AMR_STATE_QUEUE_FRZN; + sc->amr_state &= ~AMR_STATE_LD_DELETE; + sc->amr_state |= AMR_STATE_REMAP_LD; + debug(1, "State Set"); + + if (!status) { + debug(1, "disk begin destroyed %d",drv_no); + if (--amr_disks_registered == 0) + cdevsw_remove(&amrddisk_cdevsw); + debug(1, "disk begin destroyed success"); + } + return 0; +} + +static int +amr_prepare_ld_delete(struct amr_softc *sc) +{ + + debug_called(1); + if (sc->ld_del_supported == 0) + return(ENOIOCTL); + + sc->amr_state |= AMR_STATE_QUEUE_FRZN; + sc->amr_state |= AMR_STATE_LD_DELETE; + + /* 5 minutes for the all the commands to be flushed.*/ + tsleep((void *)&sc->ld_del_supported, PCATCH,"delete_logical_drv",hz * 60 * 1); + if ( sc->amr_busyslots ) + return(ENOIOCTL); + + return 0; +} +#endif + /******************************************************************************** * Accept the last close on the control device. */ static int amr_close(struct dev_close_args *ap) { - cdev_t dev = ap->a_head.a_dev; + cdev_t dev = ap->a_head.a_dev; int unit = minor(dev); struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); @@ -396,124 +517,445 @@ amr_close(struct dev_close_args *ap) /******************************************************************************** * Handle controller-specific control operations. */ +static void +amr_rescan_drives(struct cdev *dev) +{ + struct amr_softc *sc = (struct amr_softc *)dev->si_drv1; + int i, error = 0; + + sc->amr_state |= AMR_STATE_REMAP_LD; + while (sc->amr_busyslots) { + device_printf(sc->amr_dev, "idle controller\n"); + amr_done(sc); + } + + /* mark ourselves as in-shutdown */ + sc->amr_state |= AMR_STATE_SHUTDOWN; + + /* flush controller */ + device_printf(sc->amr_dev, "flushing cache..."); + kprintf("%s\n", amr_flush(sc) ? "failed" : "done"); + + /* delete all our child devices */ + for(i = 0 ; i < AMR_MAXLD; i++) { + if(sc->amr_drive[i].al_disk != 0) { + if((error = device_delete_child(sc->amr_dev, + sc->amr_drive[i].al_disk)) != 0) + goto shutdown_out; + + sc->amr_drive[i].al_disk = 0; + } + } + +shutdown_out: + amr_startup(sc); +} + +int +amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, + struct sysmsg *sm) +{ + struct amr_softc *sc = (struct amr_softc *)dev->si_drv1; + struct amr_command *ac; + struct amr_mailbox *mb; + struct amr_linux_ioctl ali; + void *dp, *temp; + int error; + int adapter, len, ac_flags = 0; + int logical_drives_changed = 0; + u_int32_t linux_version = 0x02100000; + u_int8_t status; + struct amr_passthrough *ap; /* 60 bytes */ + + error = 0; + dp = NULL; + ac = NULL; + ap = NULL; + + if ((error = copyin(addr, &ali, sizeof(ali))) != 0) + return (error); + switch (ali.ui.fcs.opcode) { + case 0x82: + switch(ali.ui.fcs.subopcode) { + case 'e': + copyout(&linux_version, (void *)(uintptr_t)ali.data, + sizeof(linux_version)); + error = 0; + break; + + case 'm': + copyout(&linux_no_adapter, (void *)(uintptr_t)ali.data, + sizeof(linux_no_adapter)); + sm->sm_result.iresult = linux_no_adapter; + error = 0; + break; + + default: + kprintf("Unknown subopcode\n"); + error = ENOIOCTL; + break; + } + break; + + case 0x80: + case 0x81: + if (ali.ui.fcs.opcode == 0x80) + len = max(ali.outlen, ali.inlen); + else + len = ali.ui.fcs.length; + + adapter = (ali.ui.fcs.adapno) ^ 'm' << 8; + + mb = (void *)&ali.mbox[0]; + + if ((ali.mbox[0] == FC_DEL_LOGDRV && ali.mbox[2] == OP_DEL_LOGDRV) || /* delete */ + (ali.mbox[0] == AMR_CMD_CONFIG && ali.mbox[2] == 0x0d)) { /* create */ + if (sc->amr_allow_vol_config == 0) { + error = EPERM; + break; + } + logical_drives_changed = 1; + } + + if (ali.mbox[0] == AMR_CMD_PASS) { + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + while ((ac = amr_alloccmd(sc)) == NULL) + lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + ap = &ac->ac_ccb->ccb_pthru; + + error = copyin((void *)(uintptr_t)mb->mb_physaddr, ap, + sizeof(struct amr_passthrough)); + if (error) + break; + + if (ap->ap_data_transfer_length) + dp = kmalloc(ap->ap_data_transfer_length, M_AMR, + M_WAITOK | M_ZERO); + + if (ali.inlen) { + error = copyin((void *)(uintptr_t)ap->ap_data_transfer_address, + dp, ap->ap_data_transfer_length); + if (error) + break; + } + + ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB; + bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox)); + ac->ac_mailbox.mb_command = AMR_CMD_PASS; + ac->ac_flags = ac_flags; + + ac->ac_data = dp; + ac->ac_length = ap->ap_data_transfer_length; + temp = (void *)(uintptr_t)ap->ap_data_transfer_address; + + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + error = amr_wait_command(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (error) + break; + + status = ac->ac_status; + error = copyout(&status, &((struct amr_passthrough *)(uintptr_t)mb->mb_physaddr)->ap_scsi_status, sizeof(status)); + if (error) + break; + + if (ali.outlen) { + error = copyout(dp, temp, ap->ap_data_transfer_length); + if (error) + break; + } + error = copyout(ap->ap_request_sense_area, ((struct amr_passthrough *)(uintptr_t)mb->mb_physaddr)->ap_request_sense_area, ap->ap_request_sense_length); + if (error) + break; + + error = 0; + break; + } else if (ali.mbox[0] == AMR_CMD_PASS_64) { + kprintf("No AMR_CMD_PASS_64\n"); + error = ENOIOCTL; + break; + } else if (ali.mbox[0] == AMR_CMD_EXTPASS) { + kprintf("No AMR_CMD_EXTPASS\n"); + error = ENOIOCTL; + break; + } else { + /* + * Bug-for-bug compatibility with Linux! + * Some apps will send commands with inlen and outlen set to 0, + * even though they expect data to be transfered to them from the + * card. Linux accidentally allows this by allocating a 4KB + * buffer for the transfer anyways, but it then throws it away + * without copying it back to the app. + */ + if (!len) + len = 4096; + + dp = kmalloc(len, M_AMR, M_WAITOK | M_ZERO); + + if (ali.inlen) { + error = copyin((void *)(uintptr_t)mb->mb_physaddr, dp, len); + if (error) + break; + } + + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + while ((ac = amr_alloccmd(sc)) == NULL) + lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz); + + ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT; + bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox)); + bcopy(&ali.mbox[0], &ac->ac_mailbox, sizeof(ali.mbox)); + + ac->ac_length = len; + ac->ac_data = dp; + ac->ac_flags = ac_flags; + + error = amr_wait_command(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (error) + break; + + status = ac->ac_status; + error = copyout(&status, &((struct amr_mailbox *)&((struct amr_linux_ioctl *)addr)->mbox[0])->mb_status, sizeof(status)); + if (ali.outlen) { + error = copyout(dp, (void *)(uintptr_t)mb->mb_physaddr, len); + if (error) + break; + } + + error = 0; + if (logical_drives_changed) + amr_rescan_drives(dev); + break; + } + break; + + default: + debug(1, "unknown linux ioctl 0x%lx", cmd); + kprintf("unknown linux ioctl 0x%lx\n", cmd); + error = ENOIOCTL; + break; + } + + /* + * At this point, we know that there is a lock held and that these + * objects have been allocated. + */ + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + if (ac != NULL) + amr_releasecmd(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (dp != NULL) + kfree(dp, M_AMR); + return(error); +} + static int amr_ioctl(struct dev_ioctl_args *ap) { - cdev_t dev = ap->a_head.a_dev; + cdev_t dev = ap->a_head.a_dev; + caddr_t addr = ap->a_data; + u_long cmd = ap->a_cmd; struct amr_softc *sc = (struct amr_softc *)dev->si_drv1; - int *arg = (int *)ap->a_data; - struct amr_user_ioctl *au = (struct amr_user_ioctl *)ap->a_data; + union { + void *_p; + struct amr_user_ioctl *au; +#ifdef AMR_IO_COMMAND32 + struct amr_user_ioctl32 *au32; +#endif + int *result; + } arg; struct amr_command *ac; struct amr_mailbox_ioctl *mbi; - struct amr_passthrough *apt; - void *dp; + void *dp, *au_buffer; + unsigned long au_length; + unsigned char *au_cmd; + int *au_statusp, au_direction; int error; + struct amr_passthrough *_ap; /* 60 bytes */ + int logical_drives_changed = 0; debug_called(1); + arg._p = (void *)addr; + error = 0; dp = NULL; - apt = NULL; ac = NULL; - switch(ap->a_cmd) { + _ap = NULL; + + switch(cmd) { case AMR_IO_VERSION: debug(1, "AMR_IO_VERSION"); - *arg = AMR_IO_VERSION_NUMBER; + *arg.result = AMR_IO_VERSION_NUMBER; + return(0); + +#ifdef AMR_IO_COMMAND32 + /* + * Accept ioctl-s from 32-bit binaries on non-32-bit + * platforms, such as AMD. LSI's MEGAMGR utility is + * the only example known today... -mi + */ + case AMR_IO_COMMAND32: + debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]); + au_cmd = arg.au32->au_cmd; + au_buffer = (void *)(u_int64_t)arg.au32->au_buffer; + au_length = arg.au32->au_length; + au_direction = arg.au32->au_direction; + au_statusp = &arg.au32->au_status; break; +#endif case AMR_IO_COMMAND: - debug(1, "AMR_IO_COMMAND 0x%x", au->au_cmd[0]); - /* handle inbound data buffer */ - if (au->au_length != 0) { - dp = kmalloc(au->au_length, M_DEVBUF, M_WAITOK); - if ((error = copyin(au->au_buffer, dp, au->au_length)) != 0) - break; - debug(2, "copyin %ld bytes from %p -> %p", au->au_length, au->au_buffer, dp); + debug(1, "AMR_IO_COMMAND 0x%x", arg.au->au_cmd[0]); + au_cmd = arg.au->au_cmd; + au_buffer = (void *)arg.au->au_buffer; + au_length = arg.au->au_length; + au_direction = arg.au->au_direction; + au_statusp = &arg.au->au_status; + break; + + case 0xc0046d00: + case 0xc06e6d00: /* Linux emulation */ + { + devclass_t devclass; + struct amr_linux_ioctl ali; + int adapter, error; + + devclass = devclass_find("amr"); + if (devclass == NULL) + return (ENOENT); + + error = copyin(addr, &ali, sizeof(ali)); + if (error) + return (error); + if (ali.ui.fcs.opcode == 0x82) + adapter = 0; + else + adapter = (ali.ui.fcs.adapno) ^ 'm' << 8; + + sc = devclass_get_softc(devclass, adapter); + if (sc == NULL) + return (ENOENT); + + return (amr_linux_ioctl_int(sc->amr_dev_t, cmd, addr, 0, ap->a_sysmsg)); } + default: + debug(1, "unknown ioctl 0x%lx", cmd); + return(ENOIOCTL); + } + + if ((au_cmd[0] == FC_DEL_LOGDRV && au_cmd[1] == OP_DEL_LOGDRV) || /* delete */ + (au_cmd[0] == AMR_CMD_CONFIG && au_cmd[1] == 0x0d)) { /* create */ + if (sc->amr_allow_vol_config == 0) { + error = EPERM; + goto out; + } + logical_drives_changed = 1; +#ifdef LSI + if ((error = amr_prepare_ld_delete(sc)) != 0) + return (error); +#endif + } - if ((ac = amr_alloccmd(sc)) == NULL) { + /* handle inbound data buffer */ + if (au_length != 0 && au_cmd[0] != 0x06) { + if ((dp = kmalloc(au_length, M_AMR, M_WAITOK|M_ZERO)) == NULL) { error = ENOMEM; - break; + goto out; + } + if ((error = copyin(au_buffer, dp, au_length)) != 0) { + kfree(dp, M_AMR); + return (error); } + debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp); + } - /* handle SCSI passthrough command */ - if (au->au_cmd[0] == AMR_CMD_PASS) { - apt = kmalloc(sizeof(*apt), M_DEVBUF, M_WAITOK | M_ZERO); - - /* copy cdb */ - apt->ap_cdb_length = au->au_cmd[2]; - bcopy(&au->au_cmd[3], &apt->ap_cdb[0], apt->ap_cdb_length); - - /* build passthrough */ - apt->ap_timeout = au->au_cmd[apt->ap_cdb_length + 3] & 0x07; - apt->ap_ars = (au->au_cmd[apt->ap_cdb_length + 3] & 0x08) ? 1 : 0; - apt->ap_islogical = (au->au_cmd[apt->ap_cdb_length + 3] & 0x80) ? 1 : 0; - apt->ap_logical_drive_no = au->au_cmd[apt->ap_cdb_length + 4]; - apt->ap_channel = au->au_cmd[apt->ap_cdb_length + 5]; - apt->ap_scsi_id = au->au_cmd[apt->ap_cdb_length + 6]; - apt->ap_request_sense_length = 14; - apt->ap_data_transfer_length = au->au_length; - /* XXX what about the request-sense area? does the caller want it? */ - - /* build command */ - ac->ac_data = apt; - ac->ac_length = sizeof(*apt); - ac->ac_flags |= AMR_CMD_DATAOUT; - ac->ac_ccb_data = dp; - ac->ac_ccb_length = au->au_length; - if (au->au_direction & AMR_IO_READ) - ac->ac_flags |= AMR_CMD_CCB_DATAIN; - if (au->au_direction & AMR_IO_WRITE) - ac->ac_flags |= AMR_CMD_CCB_DATAOUT; + /* Allocate this now before the mutex gets held */ - ac->ac_mailbox.mb_command = AMR_CMD_PASS; + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + while ((ac = amr_alloccmd(sc)) == NULL) + lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz); - } else { - /* direct command to controller */ - mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox; + /* handle SCSI passthrough command */ + if (au_cmd[0] == AMR_CMD_PASS) { + int len; - /* copy pertinent mailbox items */ - mbi->mb_command = au->au_cmd[0]; - mbi->mb_channel = au->au_cmd[1]; - mbi->mb_param = au->au_cmd[2]; - mbi->mb_pad[0] = au->au_cmd[3]; - mbi->mb_drive = au->au_cmd[4]; + _ap = &ac->ac_ccb->ccb_pthru; + bzero(_ap, sizeof(struct amr_passthrough)); - /* build the command */ - ac->ac_data = dp; - ac->ac_length = au->au_length; - if (au->au_direction & AMR_IO_READ) - ac->ac_flags |= AMR_CMD_DATAIN; - if (au->au_direction & AMR_IO_WRITE) - ac->ac_flags |= AMR_CMD_DATAOUT; - } + /* copy cdb */ + len = au_cmd[2]; + _ap->ap_cdb_length = len; + bcopy(au_cmd + 3, _ap->ap_cdb, len); - /* run the command */ - if ((error = amr_wait_command(ac)) != 0) - break; + /* build passthrough */ + _ap->ap_timeout = au_cmd[len + 3] & 0x07; + _ap->ap_ars = (au_cmd[len + 3] & 0x08) ? 1 : 0; + _ap->ap_islogical = (au_cmd[len + 3] & 0x80) ? 1 : 0; + _ap->ap_logical_drive_no = au_cmd[len + 4]; + _ap->ap_channel = au_cmd[len + 5]; + _ap->ap_scsi_id = au_cmd[len + 6]; + _ap->ap_request_sense_length = 14; + _ap->ap_data_transfer_length = au_length; + /* XXX what about the request-sense area? does the caller want it? */ - /* copy out data and set status */ - if (au->au_length != 0) - error = copyout(dp, au->au_buffer, au->au_length); - debug(2, "copyout %ld bytes from %p -> %p", au->au_length, dp, au->au_buffer); - if (dp != NULL) - debug(2, "%16d", (int)dp); - au->au_status = ac->ac_status; - break; + /* build command */ + ac->ac_mailbox.mb_command = AMR_CMD_PASS; + ac->ac_flags = AMR_CMD_CCB; - default: - debug(1, "unknown ioctl 0x%lx", cmd); - error = ENOIOCTL; - break; + } else { + /* direct command to controller */ + mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox; + + /* copy pertinent mailbox items */ + mbi->mb_command = au_cmd[0]; + mbi->mb_channel = au_cmd[1]; + mbi->mb_param = au_cmd[2]; + mbi->mb_pad[0] = au_cmd[3]; + mbi->mb_drive = au_cmd[4]; + ac->ac_flags = 0; } + /* build the command */ + ac->ac_data = dp; + ac->ac_length = au_length; + ac->ac_flags |= AMR_CMD_DATAIN|AMR_CMD_DATAOUT; + + /* run the command */ + error = amr_wait_command(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (error) + goto out; + + /* copy out data and set status */ + if (au_length != 0) { + error = copyout(dp, au_buffer, au_length); + } + debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer); if (dp != NULL) - kfree(dp, M_DEVBUF); - if (apt != NULL) - kfree(apt, M_DEVBUF); + debug(2, "%p status 0x%x", dp, ac->ac_status); + *au_statusp = ac->ac_status; + +out: + /* + * At this point, we know that there is a lock held and that these + * objects have been allocated. + */ + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); if (ac != NULL) amr_releasecmd(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (dp != NULL) + kfree(dp, M_AMR); + +#ifndef LSI + if (logical_drives_changed) + amr_rescan_drives(dev); +#endif + return(error); } @@ -558,13 +1000,7 @@ amr_query_controller(struct amr_softc *sc) struct amr_prodinfo *ap; struct amr_enquiry *ae; int ldrv; - - /* - * If we haven't found the real limit yet, let us have a couple of commands in - * order to be able to probe. - */ - if (sc->amr_maxio == 0) - sc->amr_maxio = 2; + int status; /* * Greater than 10 byte cdb support @@ -579,7 +1015,7 @@ amr_query_controller(struct amr_softc *sc) * Try to issue an ENQUIRY3 command */ if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3, - AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) { + AMR_CONFIG_ENQ3_SOLICITED_FULL, &status)) != NULL) { /* * Fetch current state of logical drives. @@ -591,12 +1027,12 @@ amr_query_controller(struct amr_softc *sc) debug(2, " drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size, sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties); } - kfree(aex, M_DEVBUF); + kfree(aex, M_AMR); /* * Get product info for channel count. */ - if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) { + if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0, &status)) == NULL) { device_printf(sc->amr_dev, "can't obtain product data from controller\n"); return(1); } @@ -604,13 +1040,20 @@ amr_query_controller(struct amr_softc *sc) sc->amr_maxchan = ap->ap_nschan; sc->amr_maxio = ap->ap_maxio; sc->amr_type |= AMR_TYPE_40LD; - kfree(ap, M_DEVBUF); - + kfree(ap, M_AMR); + + ap = amr_enquiry(sc, 0, FC_DEL_LOGDRV, OP_SUP_DEL_LOGDRV, 0, &status); + if (ap != NULL) + kfree(ap, M_AMR); + if (!status) { + sc->amr_ld_del_supported = 1; + device_printf(sc->amr_dev, "delete logical drives supported by controller\n"); + } } else { /* failed, try the 8LD ENQUIRY commands */ - if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) { - if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) { + if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0, &status)) == NULL) { + if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0, &status)) == NULL) { device_printf(sc->amr_dev, "can't obtain configuration data from controller\n"); return(1); } @@ -631,7 +1074,7 @@ amr_query_controller(struct amr_softc *sc) sc->amr_maxdrives = 8; sc->amr_maxchan = ae->ae_adapter.aa_channels; sc->amr_maxio = ae->ae_adapter.aa_maxio; - kfree(ae, M_DEVBUF); + kfree(ae, M_AMR); } /* @@ -653,7 +1096,7 @@ amr_query_controller(struct amr_softc *sc) * Run a generic enquiry-style command. */ static void * -amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual) +amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual, int *status) { struct amr_command *ac; void *result; @@ -666,12 +1109,17 @@ amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, result = NULL; /* get ourselves a command buffer */ - if ((ac = amr_alloccmd(sc)) == NULL) + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + ac = amr_alloccmd(sc); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (ac == NULL) goto out; /* allocate the response structure */ - result = kmalloc(bufsize, M_DEVBUF, M_INTWAIT); + if ((result = kmalloc(bufsize, M_AMR, M_ZERO|M_NOWAIT)) == NULL) + goto out; /* set command flags */ - ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; + + ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN; /* point the command at our data */ ac->ac_data = result; @@ -682,17 +1130,21 @@ amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, mbox[0] = cmd; mbox[2] = cmdsub; mbox[3] = cmdqual; + *status = 0; /* can't assume that interrupts are going to work here, so play it safe */ if (sc->amr_poll_command(ac)) goto out; error = ac->ac_status; + *status = ac->ac_status; out: + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); if (ac != NULL) amr_releasecmd(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); if ((error != 0) && (result != NULL)) { - kfree(result, M_DEVBUF); + kfree(result, M_AMR); result = NULL; } return(result); @@ -709,7 +1161,10 @@ amr_flush(struct amr_softc *sc) /* get ourselves a command buffer */ error = 1; - if ((ac = amr_alloccmd(sc)) == NULL) + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + ac = amr_alloccmd(sc); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (ac == NULL) goto out; /* set command flags */ ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; @@ -723,8 +1178,10 @@ amr_flush(struct amr_softc *sc) error = ac->ac_status; out: + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); if (ac != NULL) amr_releasecmd(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); return(error); } @@ -742,7 +1199,10 @@ amr_support_ext_cdb(struct amr_softc *sc) /* get ourselves a command buffer */ error = 0; - if ((ac = amr_alloccmd(sc)) == NULL) + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + ac = amr_alloccmd(sc); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (ac == NULL) goto out; /* set command flags */ ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; @@ -761,8 +1221,10 @@ amr_support_ext_cdb(struct amr_softc *sc) } out: + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); if (ac != NULL) amr_releasecmd(ac); + lockmgr(&sc->amr_list_lock, LK_RELEASE); return(error); } @@ -781,6 +1243,10 @@ amr_startio(struct amr_softc *sc) /* spin until something prevents us from doing any work */ for (;;) { + /* Don't bother to queue commands no bounce buffers are available. */ + if (sc->amr_state & AMR_STATE_QUEUE_FRZN) + break; + /* try to get a ready command */ ac = amr_dequeue_ready(sc); @@ -789,8 +1255,8 @@ amr_startio(struct amr_softc *sc) (void)amr_bio_command(sc, &ac); /* if that failed, build a command from a ccb */ - if (ac == NULL) - (void)amr_cam_command(sc, &ac); + if ((ac == NULL) && (sc->amr_cam_command != NULL)) + sc->amr_cam_command(sc, &ac); /* if we don't have anything to do, give up */ if (ac == NULL) @@ -811,17 +1277,23 @@ amr_startio(struct amr_softc *sc) static void amr_completeio(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; - + struct amr_softc *sc = ac->ac_sc; + static struct timeval lastfail; + static int curfail; + struct buf *bp = ac->ac_bio->bio_buf; + if (ac->ac_status != AMR_STATUS_SUCCESS) { /* could be more verbose here? */ - ac->ac_bio->bio_buf->b_error = EIO; - ac->ac_bio->bio_buf->b_flags |= B_ERROR; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; - device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status); + if (ppsratecheck(&lastfail, &curfail, 1)) + device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status); /* amr_printcommand(ac);*/ } amrd_intr(ac->ac_bio); + lockmgr(&ac->ac_sc->amr_list_lock, LK_EXCLUSIVE); amr_releasecmd(ac); + lockmgr(&ac->ac_sc->amr_list_lock, LK_RELEASE); } /******************************************************************************** @@ -839,73 +1311,78 @@ amr_bio_command(struct amr_softc *sc, struct amr_command **acp) struct amr_command *ac; struct amrd_softc *amrd; struct bio *bio; + struct buf *bp; int error; int blkcount; int driveno; int cmd; - u_int64_t lba; ac = NULL; error = 0; + /* get a command */ + if ((ac = amr_alloccmd(sc)) == NULL) + return (ENOMEM); + /* get a bio to work on */ - if ((bio = amr_dequeue_bio(sc)) == NULL) - goto out; + if ((bio = amr_dequeue_bio(sc)) == NULL) { + amr_releasecmd(ac); + return (0); + } - /* get a command */ - if ((ac = amr_alloccmd(sc)) == NULL) { - error = ENOMEM; - goto out; - } - /* connect the bio to the command */ + bp = bio->bio_buf; ac->ac_complete = amr_completeio; ac->ac_bio = bio; - ac->ac_data = bio->bio_buf->b_data; - ac->ac_length = bio->bio_buf->b_bcount; - - switch (bio->bio_buf->b_cmd) { + ac->ac_data = bp->b_data; + ac->ac_length = bp->b_bcount; + cmd = 0; + switch (bp->b_cmd) { case BUF_CMD_READ: ac->ac_flags |= AMR_CMD_DATAIN; - cmd = AMR_CMD_LREAD; + if (AMR_IS_SG64(sc)) { + cmd = AMR_CMD_LREAD64; + ac->ac_flags |= AMR_CMD_SG64; + } else + cmd = AMR_CMD_LREAD; break; case BUF_CMD_WRITE: ac->ac_flags |= AMR_CMD_DATAOUT; - cmd = AMR_CMD_LWRITE; + if (AMR_IS_SG64(sc)) { + cmd = AMR_CMD_LWRITE64; + ac->ac_flags |= AMR_CMD_SG64; + } else + cmd = AMR_CMD_LWRITE; break; case BUF_CMD_FLUSH: ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; cmd = AMR_CMD_FLUSH; break; default: - cmd = 0; - break; + panic("Invalid bio command"); } amrd = (struct amrd_softc *)bio->bio_driver_info; driveno = amrd->amrd_drive - sc->amr_drive; - blkcount = (bio->bio_buf->b_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE; - - lba = bio->bio_offset / AMR_BLKSIZE; - KKASSERT(lba < 0x100000000ULL); + blkcount = (bp->b_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE; ac->ac_mailbox.mb_command = cmd; - ac->ac_mailbox.mb_blkcount = blkcount; - ac->ac_mailbox.mb_lba = lba; + if (bp->b_cmd & (BUF_CMD_READ|BUF_CMD_WRITE)) { + ac->ac_mailbox.mb_blkcount = blkcount; + ac->ac_mailbox.mb_lba = bio->bio_offset / AMR_BLKSIZE; + if (((bio->bio_offset / AMR_BLKSIZE) + blkcount) > sc->amr_drive[driveno].al_size) { + device_printf(sc->amr_dev, + "I/O beyond end of unit (%lld,%d > %lu)\n", + (long long)(bio->bio_offset / AMR_BLKSIZE), blkcount, + (u_long)sc->amr_drive[driveno].al_size); + } + } ac->ac_mailbox.mb_drive = driveno; + if (sc->amr_state & AMR_STATE_REMAP_LD) + ac->ac_mailbox.mb_drive |= 0x80; + /* we fill in the s/g related data when the command is mapped */ - if ((lba + blkcount) > sc->amr_drive[driveno].al_size) - device_printf(sc->amr_dev, "I/O beyond end of unit (%ju,%d > %lu)\n", - (uintmax_t)lba, blkcount, - (u_long)sc->amr_drive[driveno].al_size); -out: - if (error != 0) { - if (ac != NULL) - amr_releasecmd(ac); - if (bio != NULL) /* this breaks ordering... */ - amr_enqueue_bio(sc, bio); - } *acp = ac; return(error); } @@ -917,21 +1394,22 @@ out: static int amr_wait_command(struct amr_command *ac) { - int error, count; - + int error = 0; + struct amr_softc *sc = ac->ac_sc; + debug_called(1); ac->ac_complete = NULL; ac->ac_flags |= AMR_CMD_SLEEP; - if ((error = amr_start(ac)) != 0) + if ((error = amr_start(ac)) != 0) { return(error); + } - count = 0; - /* XXX better timeout? */ - while ((ac->ac_flags & AMR_CMD_BUSY) && (count < 30)) { - tsleep(ac, PCATCH, "amrwcmd", hz); + while ((ac->ac_flags & AMR_CMD_BUSY) && (error != EWOULDBLOCK)) { + error = lksleep(ac,&sc->amr_list_lock, 0, "amrwcmd", 0); } - return(0); + + return(error); } /******************************************************************************** @@ -969,6 +1447,38 @@ amr_std_poll_command(struct amr_command *ac) return(error); } +static void +amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) +{ + struct amr_command *ac = arg; + struct amr_softc *sc = ac->ac_sc; + int mb_channel; + + if (err) { + device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__); + ac->ac_status = AMR_STATUS_ABORTED; + return; + } + + amr_setup_sg(arg, segs, nsegs, err); + + /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ + mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel; + if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && + ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) || + (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG))) + ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments; + + ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments; + ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr; + if (AC_IS_SG64(ac)) { + ac->ac_sg64_hi = 0; + ac->ac_sg64_lo = ac->ac_sgbusaddr; + } + + sc->amr_poll_command1(sc, ac); +} + /******************************************************************************** * Take a command, submit it to the controller and busy-wait for it to return. * Returns nonzero on error. Can be safely called with interrupts enabled. @@ -977,31 +1487,57 @@ static int amr_quartz_poll_command(struct amr_command *ac) { struct amr_softc *sc = ac->ac_sc; - int error,count; + int error; debug_called(2); + error = 0; + + if (AC_IS_SG64(ac)) { + ac->ac_tag = sc->amr_buffer64_dmat; + ac->ac_datamap = ac->ac_dma64map; + } else { + ac->ac_tag = sc->amr_buffer_dmat; + ac->ac_datamap = ac->ac_dmamap; + } + /* now we have a slot, we can map the command (unmapped in amr_complete) */ - amr_mapcmd(ac); + if (ac->ac_data != NULL && ac->ac_length != 0) { + if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data, + ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) { + error = 1; + } + } else { + error = amr_quartz_poll_command1(sc, ac); + } - crit_enter(); + return (error); +} - if (sc->amr_state & AMR_STATE_INTEN) { - count=0; - while (sc->amr_busyslots) { - tsleep(sc, PCATCH, "amrpoll", hz); - if(count++>10) { - break; - } +static int +amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac) +{ + int count, error; + + lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE); + if ((sc->amr_state & AMR_STATE_INTEN) == 0) { + count=0; + while (sc->amr_busyslots) { + lksleep(sc, &sc->amr_hw_lock, PCATCH, "amrpoll", hz); + if(count++>10) { + break; } - - if(sc->amr_busyslots) { - device_printf(sc->amr_dev, "adapter is busy\n"); - crit_exit(); - amr_unmapcmd(ac); - ac->ac_status=0; - return(1); + } + + if(sc->amr_busyslots) { + device_printf(sc->amr_dev, "adapter is busy\n"); + lockmgr(&sc->amr_hw_lock, LK_RELEASE); + if (ac->ac_data != NULL) { + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); } + ac->ac_status=0; + return(1); + } } bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE); @@ -1016,65 +1552,51 @@ amr_quartz_poll_command(struct amr_command *ac) AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT); - while(sc->amr_mailbox->mb_nstatus == 0xFF); - while(sc->amr_mailbox->mb_status == 0xFF); + while(sc->amr_mailbox->mb_nstatus == 0xFF) + DELAY(1); + while(sc->amr_mailbox->mb_status == 0xFF) + DELAY(1); ac->ac_status=sc->amr_mailbox->mb_status; error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0; - while(sc->amr_mailbox->mb_poll != 0x77); + while(sc->amr_mailbox->mb_poll != 0x77) + DELAY(1); sc->amr_mailbox->mb_poll = 0; sc->amr_mailbox->mb_ack = 0x77; /* acknowledge that we have the commands */ AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK); - while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK); - - crit_exit(); + while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK) + DELAY(1); + lockmgr(&sc->amr_hw_lock, LK_RELEASE); /* unmap the command's data buffer */ - amr_unmapcmd(ac); + if (ac->ac_flags & AMR_CMD_DATAIN) { + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTREAD); + } + if (ac->ac_flags & AMR_CMD_DATAOUT) { + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTWRITE); + } + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); return(error); } -/******************************************************************************** - * Get a free command slot for a command if it doesn't already have one. - * - * May be safely called multiple times for a given command. - */ -static int -amr_getslot(struct amr_command *ac) +static __inline int +amr_freeslot(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; - int slot, limit, error; + struct amr_softc *sc = ac->ac_sc; + int slot; debug_called(3); - /* if the command already has a slot, don't try to give it another one */ - if (ac->ac_slot != 0) - return(0); + slot = ac->ac_slot; + if (sc->amr_busycmd[slot] == NULL) + panic("amr: slot %d not busy?\n", slot); - /* enforce slot usage limit */ - limit = (ac->ac_flags & AMR_CMD_PRIORITY) ? sc->amr_maxio : sc->amr_maxio - 4; - if (sc->amr_busyslots > limit) - return(EBUSY); - - /* - * Allocate a slot. XXX linear scan is slow - */ - error = EBUSY; - crit_enter(); - for (slot = 0; slot < sc->amr_maxio; slot++) { - if (sc->amr_busycmd[slot] == NULL) { - sc->amr_busycmd[slot] = ac; - sc->amr_busyslots++; - ac->ac_slot = slot; - error = 0; - break; - } - } - crit_exit(); + sc->amr_busycmd[slot] = NULL; + atomic_subtract_int(&sc->amr_busyslots, 1); - return(error); + return (0); } /******************************************************************************** @@ -1083,132 +1605,166 @@ amr_getslot(struct amr_command *ac) * These functions may be safely called multiple times on a given command. */ static void -amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) +amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error) { struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; struct amr_sgentry *sg; - int i; - u_int8_t *sgc; + struct amr_sg64entry *sg64; + int flags, i; debug_called(3); /* get base address of s/g table */ - sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); + sg = ac->ac_sg.sg32; + sg64 = ac->ac_sg.sg64; + + if (AC_IS_SG64(ac)) { + ac->ac_nsegments = nsegments; + ac->ac_mb_physaddr = 0xffffffff; + for (i = 0; i < nsegments; i++, sg64++) { + sg64->sg_addr = segs[i].ds_addr; + sg64->sg_count = segs[i].ds_len; + } + } else { + /* decide whether we need to populate the s/g table */ + if (nsegments < 2) { + ac->ac_nsegments = 0; + ac->ac_mb_physaddr = segs[0].ds_addr; + } else { + ac->ac_nsegments = nsegments; + ac->ac_mb_physaddr = ac->ac_sgbusaddr; + for (i = 0; i < nsegments; i++, sg++) { + sg->sg_addr = segs[i].ds_addr; + sg->sg_count = segs[i].ds_len; + } + } + } - /* save data physical address */ - ac->ac_dataphys = segs[0].ds_addr; + flags = 0; + if (ac->ac_flags & AMR_CMD_DATAIN) + flags |= BUS_DMASYNC_PREREAD; + if (ac->ac_flags & AMR_CMD_DATAOUT) + flags |= BUS_DMASYNC_PREWRITE; + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flags); + ac->ac_flags |= AMR_CMD_MAPPED; +} - /* for AMR_CMD_CONFIG the s/g count goes elsewhere */ - if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) { - sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param); - } else { - sgc = &ac->ac_mailbox.mb_nsgelem; +static void +amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegs, int err) +{ + struct amr_command *ac = arg; + struct amr_softc *sc = ac->ac_sc; + int mb_channel; + + if (err) { + device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__); + amr_abort_load(ac); + return; } - /* decide whether we need to populate the s/g table */ - if (nsegments < 2) { - *sgc = 0; - ac->ac_mailbox.mb_nsgelem = 0; - ac->ac_mailbox.mb_physaddr = ac->ac_dataphys; - } else { - ac->ac_mailbox.mb_nsgelem = nsegments; - *sgc = nsegments; - ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - } + amr_setup_sg(arg, segs, nsegs, err); + + /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ + mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel; + if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && + ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) || + (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG))) + ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments; + + ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments; + ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr; + if (AC_IS_SG64(ac)) { + ac->ac_sg64_hi = 0; + ac->ac_sg64_lo = ac->ac_sgbusaddr; + } + + if (sc->amr_submit_command(ac) == EBUSY) { + amr_freeslot(ac); + amr_requeue_ready(ac); } } static void -amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) +amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { - struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; - struct amr_sgentry *sg; - struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data; - struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data; - int i; + struct amr_command *ac = arg; + struct amr_softc *sc = ac->ac_sc; + struct amr_passthrough *ap = &ac->ac_ccb->ccb_pthru; + struct amr_ext_passthrough *aep = &ac->ac_ccb->ccb_epthru; + + if (err) { + device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__); + amr_abort_load(ac); + return; + } - /* get base address of s/g table */ - sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); + /* Set up the mailbox portion of the command to point at the ccb */ + ac->ac_mailbox.mb_nsgelem = 0; + ac->ac_mailbox.mb_physaddr = ac->ac_ccb_busaddr; - /* decide whether we need to populate the s/g table */ - if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) { - if (nsegments < 2) { - aep->ap_no_sg_elements = 0; - aep->ap_data_transfer_address = segs[0].ds_addr; - } else { - /* save s/g table information in passthrough */ - aep->ap_no_sg_elements = nsegments; - aep->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); - /* populate s/g table (overwrites previous call which mapped the passthrough) */ - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); - } - } - debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot, - aep->ap_no_sg_elements, aep->ap_data_transfer_address, ac->ac_dataphys); - } else { - if (nsegments < 2) { - ap->ap_no_sg_elements = 0; - ap->ap_data_transfer_address = segs[0].ds_addr; - } else { - /* save s/g table information in passthrough */ - ap->ap_no_sg_elements = nsegments; - ap->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); - /* populate s/g table (overwrites previous call which mapped the passthrough) */ - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); - } - } - debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot, - ap->ap_no_sg_elements, ap->ap_data_transfer_address, ac->ac_dataphys); + amr_setup_sg(arg, segs, nsegs, err); + + switch (ac->ac_mailbox.mb_command) { + case AMR_CMD_EXTPASS: + aep->ap_no_sg_elements = ac->ac_nsegments; + aep->ap_data_transfer_address = ac->ac_mb_physaddr; + break; + case AMR_CMD_PASS: + ap->ap_no_sg_elements = ac->ac_nsegments; + ap->ap_data_transfer_address = ac->ac_mb_physaddr; + break; + default: + panic("Unknown ccb command"); + } + + if (sc->amr_submit_command(ac) == EBUSY) { + amr_freeslot(ac); + amr_requeue_ready(ac); } } -static void +static int amr_mapcmd(struct amr_command *ac) { + bus_dmamap_callback_t *cb; struct amr_softc *sc = ac->ac_sc; debug_called(3); - /* if the command involves data at all, and hasn't been mapped */ - if (!(ac->ac_flags & AMR_CMD_MAPPED)) { + if (AC_IS_SG64(ac)) { + ac->ac_tag = sc->amr_buffer64_dmat; + ac->ac_datamap = ac->ac_dma64map; + } else { + ac->ac_tag = sc->amr_buffer_dmat; + ac->ac_datamap = ac->ac_dmamap; + } - if (ac->ac_data != NULL) { - /* map the data buffers into bus space and build the s/g list */ - bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, ac->ac_length, - amr_setup_dmamap, ac, 0); - if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREWRITE); - } + if (ac->ac_flags & AMR_CMD_CCB) + cb = amr_setup_ccb; + else + cb = amr_setup_data; - if (ac->ac_ccb_data != NULL) { - bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, ac->ac_ccb_data, ac->ac_ccb_length, - amr_setup_ccbmap, ac, 0); - if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREWRITE); + /* if the command involves data at all, and hasn't been mapped */ + if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) { + /* map the data buffers into bus space and build the s/g list */ + if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data, + ac->ac_length, cb, ac, 0) == EINPROGRESS) { + sc->amr_state |= AMR_STATE_QUEUE_FRZN; } - ac->ac_flags |= AMR_CMD_MAPPED; - } + } else { + if (sc->amr_submit_command(ac) == EBUSY) { + amr_freeslot(ac); + amr_requeue_ready(ac); + } + } + + return (0); } static void amr_unmapcmd(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; + int flag; debug_called(3); @@ -1216,24 +1772,38 @@ amr_unmapcmd(struct amr_command *ac) if (ac->ac_flags & AMR_CMD_MAPPED) { if (ac->ac_data != NULL) { + + flag = 0; if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD); + flag |= BUS_DMASYNC_POSTREAD; if (ac->ac_flags & AMR_CMD_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); - } + flag |= BUS_DMASYNC_POSTWRITE; - if (ac->ac_ccb_data != NULL) { - if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTREAD); - if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap); + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flag); + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); } + ac->ac_flags &= ~AMR_CMD_MAPPED; } } +static void +amr_abort_load(struct amr_command *ac) +{ + ac_qhead_t head; + struct amr_softc *sc = ac->ac_sc; + + KKASSERT(lockstatus(&sc->amr_list_lock, curthread) != 0); + + ac->ac_status = AMR_STATUS_ABORTED; + amr_init_qhead(&head); + amr_enqueue_completed(ac, &head); + + lockmgr(&sc->amr_list_lock, LK_RELEASE); + amr_complete(sc, &head); + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); +} + /******************************************************************************** * Take a command and give it to the controller, returns 0 if successful, or * EBUSY if the command should be retried later. @@ -1241,79 +1811,33 @@ amr_unmapcmd(struct amr_command *ac) static int amr_start(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; - int done, i; + struct amr_softc *sc; + int error = 0; + int slot; debug_called(3); /* mark command as busy so that polling consumer can tell */ + sc = ac->ac_sc; ac->ac_flags |= AMR_CMD_BUSY; /* get a command slot (freed in amr_done) */ - if (amr_getslot(ac)) - return(EBUSY); - - /* now we have a slot, we can map the command (unmapped in amr_complete) */ - amr_mapcmd(ac); - - /* mark the new mailbox we are going to copy in as busy */ - ac->ac_mailbox.mb_busy = 1; - - /* clear the poll/ack fields in the mailbox */ - sc->amr_mailbox->mb_poll = 0; - sc->amr_mailbox->mb_ack = 0; - - /* - * Save the slot number so that we can locate this command when complete. - * Note that ident = 0 seems to be special, so we don't use it. - */ - ac->ac_mailbox.mb_ident = ac->ac_slot + 1; - - /* - * Spin waiting for the mailbox, give up after ~1 second. We expect the - * controller to be able to handle our I/O. - * - * XXX perhaps we should wait for less time, and count on the deferred command - * handling to deal with retries? - */ - debug(4, "wait for mailbox"); - for (i = 10000, done = 0; (i > 0) && !done; i--) { - crit_enter(); - - /* is the mailbox free? */ - if (sc->amr_mailbox->mb_busy == 0) { - debug(4, "got mailbox"); - sc->amr_mailbox64->mb64_segment = 0; - bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE); - done = 1; - - /* not free, spin waiting */ - } else { - debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy); - /* this is somewhat ugly */ - DELAY(100); - } - crit_exit(); + slot = ac->ac_slot; + if (sc->amr_busycmd[slot] != NULL) + panic("amr: slot %d busy?\n", slot); + sc->amr_busycmd[slot] = ac; + atomic_add_int(&sc->amr_busyslots, 1); + + /* Now we have a slot, we can map the command (unmapped in amr_complete). */ + if ((error = amr_mapcmd(ac)) == ENOMEM) { + /* + * Memroy resources are short, so free the slot and let this be tried + * later. + */ + amr_freeslot(ac); } - /* - * Now give the command to the controller - */ - if (done) { - if (sc->amr_submit_command(sc)) { - /* the controller wasn't ready to take the command, forget that we tried to post it */ - sc->amr_mailbox->mb_busy = 0; - return(EBUSY); - } - debug(3, "posted command"); - return(0); - } - - /* - * The controller wouldn't take the command. Return the command as busy - * so that it is retried later. - */ - return(EBUSY); + return (error); } /******************************************************************************** @@ -1321,9 +1845,11 @@ amr_start(struct amr_command *ac) * * Returns nonzero if any commands on the work queue were marked as completed. */ + int amr_done(struct amr_softc *sc) { + ac_qhead_t head; struct amr_command *ac; struct amr_mailbox mbox; int i, idx, result; @@ -1332,6 +1858,7 @@ amr_done(struct amr_softc *sc) /* See if there's anything for us to do */ result = 0; + amr_init_qhead(&head); /* loop collecting completed commands */ for (;;) { @@ -1349,42 +1876,32 @@ amr_done(struct amr_softc *sc) if (ac != NULL) { /* pull the command from the busy index */ - sc->amr_busycmd[idx] = NULL; - sc->amr_busyslots--; + amr_freeslot(ac); /* save status for later use */ ac->ac_status = mbox.mb_status; - amr_enqueue_completed(ac); + amr_enqueue_completed(ac, &head); debug(3, "completed command with status %x", mbox.mb_status); } else { device_printf(sc->amr_dev, "bad slot %d completed\n", idx); } } - } else { + } else break; /* no work */ - } } - - /* if we've completed any commands, try posting some more */ - if (result) - amr_startio(sc); - + /* handle completion and timeouts */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 - if (sc->amr_state & AMR_STATE_INTEN) - taskqueue_enqueue(taskqueue_swi, &sc->amr_task_complete); - else -#endif - amr_complete(sc, 0); - + amr_complete(sc, &head); + return(result); } /******************************************************************************** * Do completion processing on done commands on (sc) */ + static void -amr_complete(void *context, int pending) +amr_complete(void *context, ac_qhead_t *head) { struct amr_softc *sc = (struct amr_softc *)context; struct amr_command *ac; @@ -1393,33 +1910,43 @@ amr_complete(void *context, int pending) /* pull completed commands off the queue */ for (;;) { - ac = amr_dequeue_completed(sc); + ac = amr_dequeue_completed(sc, head); if (ac == NULL) break; /* unmap the command's data buffer */ amr_unmapcmd(ac); - /* unbusy the command */ - ac->ac_flags &= ~AMR_CMD_BUSY; - /* * Is there a completion handler? */ if (ac->ac_complete != NULL) { + /* unbusy the command */ + ac->ac_flags &= ~AMR_CMD_BUSY; ac->ac_complete(ac); /* * Is someone sleeping on this one? */ - } else if (ac->ac_flags & AMR_CMD_SLEEP) { - wakeup(ac); + } else { + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + ac->ac_flags &= ~AMR_CMD_BUSY; + if (ac->ac_flags & AMR_CMD_SLEEP) { + /* unbusy the command */ + wakeup(ac); + } + lockmgr(&sc->amr_list_lock, LK_RELEASE); } if(!sc->amr_busyslots) { wakeup(sc); } } + + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + sc->amr_state &= ~AMR_STATE_QUEUE_FRZN; + amr_startio(sc); + lockmgr(&sc->amr_list_lock, LK_RELEASE); } /******************************************************************************** @@ -1444,21 +1971,20 @@ amr_alloccmd(struct amr_softc *sc) ac = amr_dequeue_free(sc); if (ac == NULL) { - amr_alloccmd_cluster(sc); - ac = amr_dequeue_free(sc); - } - if (ac == NULL) + sc->amr_state |= AMR_STATE_QUEUE_FRZN; return(NULL); + } /* clear out significant fields */ - ac->ac_slot = 0; ac->ac_status = 0; bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox)); ac->ac_flags = 0; ac->ac_bio = NULL; ac->ac_data = NULL; - ac->ac_ccb_data = NULL; ac->ac_complete = NULL; + ac->ac_retries = 0; + ac->ac_tag = NULL; + ac->ac_datamap = NULL; return(ac); } @@ -1481,19 +2007,58 @@ amr_alloccmd_cluster(struct amr_softc *sc) { struct amr_command_cluster *acc; struct amr_command *ac; - int i; + int i, nextslot; - acc = kmalloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_INTWAIT); - crit_enter(); - TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link); - crit_exit(); - for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) { - ac = &acc->acc_command[i]; - bzero(ac, sizeof(*ac)); - ac->ac_sc = sc; - if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) && - !bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap)) + /* + * If we haven't found the real limit yet, let us have a couple of + * commands in order to be able to probe. + */ + if (sc->amr_maxio == 0) + sc->amr_maxio = 2; + + if (sc->amr_nextslot > sc->amr_maxio) + return; + acc = kmalloc(AMR_CMD_CLUSTERSIZE, M_AMR, M_NOWAIT | M_ZERO); + if (acc != NULL) { + nextslot = sc->amr_nextslot; + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) { + ac = &acc->acc_command[i]; + ac->ac_sc = sc; + ac->ac_slot = nextslot; + + /* + * The SG table for each slot is a fixed size and is assumed to + * to hold 64-bit s/g objects when the driver is configured to do + * 64-bit DMA. 32-bit DMA commands still use the same table, but + * cast down to 32-bit objects. + */ + if (AMR_IS_SG64(sc)) { + ac->ac_sgbusaddr = sc->amr_sgbusaddr + + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sg64entry)); + ac->ac_sg.sg64 = sc->amr_sg64table + (ac->ac_slot * AMR_NSEG); + } else { + ac->ac_sgbusaddr = sc->amr_sgbusaddr + + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); + ac->ac_sg.sg32 = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); + } + + ac->ac_ccb = sc->amr_ccb + ac->ac_slot; + ac->ac_ccb_busaddr = sc->amr_ccb_busaddr + + (ac->ac_slot * sizeof(union amr_ccb)); + + if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap)) + break; + if (AMR_IS_SG64(sc) && + (bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map))) + break; amr_releasecmd(ac); + if (++nextslot > sc->amr_maxio) + break; + } + sc->amr_nextslot = nextslot; } } @@ -1506,9 +2071,14 @@ amr_freecmd_cluster(struct amr_command_cluster *acc) struct amr_softc *sc = acc->acc_command[0].ac_sc; int i; - for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) + for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) { + if (acc->acc_command[i].ac_sc == NULL) + break; bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap); - kfree(acc, M_DEVBUF); + if (AMR_IS_SG64(sc)) + bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_dma64map); + } + kfree(acc, M_AMR); } /******************************************************************************** @@ -1521,24 +2091,78 @@ amr_freecmd_cluster(struct amr_command_cluster *acc) * Tell the controller that the mailbox contains a valid command */ static int -amr_quartz_submit_command(struct amr_softc *sc) +amr_quartz_submit_command(struct amr_command *ac) { - debug_called(3); + struct amr_softc *sc = ac->ac_sc; + static struct timeval lastfail; + static int curfail; + int i = 0; + + lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE); + while (sc->amr_mailbox->mb_busy && (i++ < 10)) { + DELAY(1); + /* This is a no-op read that flushes pending mailbox updates */ + AMR_QGET_ODB(sc); + } + if (sc->amr_mailbox->mb_busy) { + lockmgr(&sc->amr_hw_lock, LK_RELEASE); + if (ac->ac_retries++ > 1000) { + if (ppsratecheck(&lastfail, &curfail, 1)) + device_printf(sc->amr_dev, "Too many retries on command %p. " + "Controller is likely dead\n", ac); + ac->ac_retries = 0; + } + return (EBUSY); + } + + /* + * Save the slot number so that we can locate this command when complete. + * Note that ident = 0 seems to be special, so we don't use it. + */ + ac->ac_mailbox.mb_ident = ac->ac_slot + 1; /* will be coppied into mbox */ + bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, 14); + sc->amr_mailbox->mb_busy = 1; + sc->amr_mailbox->mb_poll = 0; + sc->amr_mailbox->mb_ack = 0; + sc->amr_mailbox64->sg64_hi = ac->ac_sg64_hi; + sc->amr_mailbox64->sg64_lo = ac->ac_sg64_lo; - if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT) - return(EBUSY); AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT); + lockmgr(&sc->amr_hw_lock, LK_RELEASE); return(0); } static int -amr_std_submit_command(struct amr_softc *sc) +amr_std_submit_command(struct amr_command *ac) { - debug_called(3); + struct amr_softc *sc = ac->ac_sc; + static struct timeval lastfail; + static int curfail; + + lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE); + if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG) { + lockmgr(&sc->amr_hw_lock, LK_RELEASE); + if (ac->ac_retries++ > 1000) { + if (ppsratecheck(&lastfail, &curfail, 1)) + device_printf(sc->amr_dev, "Too many retries on command %p. " + "Controller is likely dead\n", ac); + ac->ac_retries = 0; + } + return (EBUSY); + } + + /* + * Save the slot number so that we can locate this command when complete. + * Note that ident = 0 seems to be special, so we don't use it. + */ + ac->ac_mailbox.mb_ident = ac->ac_slot + 1; /* will be coppied into mbox */ + bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, 14); + sc->amr_mailbox->mb_busy = 1; + sc->amr_mailbox->mb_poll = 0; + sc->amr_mailbox->mb_ack = 0; - if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG) - return(EBUSY); AMR_SPOST_COMMAND(sc); + lockmgr(&sc->amr_hw_lock, LK_RELEASE); return(0); } @@ -1549,26 +2173,44 @@ amr_std_submit_command(struct amr_softc *sc) static int amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) { - int worked; + int worked, i; u_int32_t outd; + u_int8_t nstatus; + u_int8_t completed[46]; debug_called(3); worked = 0; - crit_enter(); /* work waiting for us? */ if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) { - /* save mailbox, which contains a list of completed commands */ - bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave)); - /* acknowledge interrupt */ AMR_QPUT_ODB(sc, AMR_QODB_READY); + while ((nstatus = sc->amr_mailbox->mb_nstatus) == 0xff) + DELAY(1); + sc->amr_mailbox->mb_nstatus = 0xff; + + /* wait until fw wrote out all completions */ + for (i = 0; i < nstatus; i++) { + while ((completed[i] = sc->amr_mailbox->mb_completed[i]) == 0xff) + DELAY(1); + sc->amr_mailbox->mb_completed[i] = 0xff; + } + + /* Save information for later processing */ + mbsave->mb_nstatus = nstatus; + mbsave->mb_status = sc->amr_mailbox->mb_status; + sc->amr_mailbox->mb_status = 0xff; + + for (i = 0; i < nstatus; i++) + mbsave->mb_completed[i] = completed[i]; + /* acknowledge that we have the commands */ - AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK); + AMR_QPUT_IDB(sc, AMR_QIDB_ACK); +#if 0 #ifndef AMR_QUARTZ_GOFASTER /* * This waits for the controller to notice that we've taken the @@ -1581,12 +2223,12 @@ amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) */ while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK) ; /* XXX aiee! what if it dies? */ +#endif #endif worked = 1; /* got some work */ } - crit_exit(); return(worked); } @@ -1599,7 +2241,6 @@ amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) debug_called(3); worked = 0; - crit_enter(); /* check for valid interrupt status */ istat = AMR_SGET_ISTAT(sc); @@ -1613,7 +2254,6 @@ amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) worked = 1; } - crit_exit(); return(worked); } @@ -1710,26 +2350,27 @@ amr_describe_controller(struct amr_softc *sc) struct amr_prodinfo *ap; struct amr_enquiry *ae; char *prod; + int status; /* * Try to get 40LD product info, which tells us what the card is labelled as. */ - if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) { + if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0, &status)) != NULL) { device_printf(sc->amr_dev, " Firmware %.16s, BIOS %.16s, %dMB RAM\n", ap->ap_product, ap->ap_firmware, ap->ap_bios, ap->ap_memsize); - kfree(ap, M_DEVBUF); + kfree(ap, M_AMR); return; } /* * Try 8LD extended ENQUIRY to get controller signature, and use lookup table. */ - if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) { + if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0, &status)) != NULL) { prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature); - } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) { + } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0, &status)) != NULL) { /* * Try to work it out based on the PCI signatures. @@ -1786,19 +2427,18 @@ amr_describe_controller(struct amr_softc *sc) prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios, ae->ae_adapter.aa_memorysize); } - kfree(ae, M_DEVBUF); + kfree(ae, M_AMR); } int -amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int blks) +amr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks) { - struct amr_command *ac; - int error = 1; + int error = EIO; debug_called(1); - sc->amr_state &= ~AMR_STATE_INTEN; + sc->amr_state |= AMR_STATE_INTEN; /* get ourselves a command buffer */ if ((ac = amr_alloccmd(sc)) == NULL) @@ -1815,7 +2455,7 @@ amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int b ac->ac_mailbox.mb_blkcount = blks; ac->ac_mailbox.mb_lba = lba; ac->ac_mailbox.mb_drive = unit; - + /* can't assume that interrupts are going to work here, so play it safe */ if (sc->amr_poll_command(ac)) goto out; @@ -1825,12 +2465,12 @@ amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int b if (ac != NULL) amr_releasecmd(ac); - sc->amr_state |= AMR_STATE_INTEN; - - return (error); + sc->amr_state &= ~AMR_STATE_INTEN; + return (error); } + #ifdef AMR_DEBUG /******************************************************************************** * Print the command (ac) in human-readable format diff --git a/sys/dev/raid/amr/amr_cam.c b/sys/dev/raid/amr/amr_cam.c index 62979881a1..ed5da501b4 100644 --- a/sys/dev/raid/amr/amr_cam.c +++ b/sys/dev/raid/amr/amr_cam.c @@ -7,10 +7,10 @@ * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -23,7 +23,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + */ +/*- * Copyright (c) 2002 Eric Moore * Copyright (c) 2002 LSI Logic Corporation * All rights reserved. @@ -32,13 +33,13 @@ * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * 3. The party using or redistributing the source code and binary forms - * agrees to the disclaimer below and the terms and conditions set forth - * herein. + * agrees to the disclaimer below and the terms and conditions set forth + * herein. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -52,20 +53,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amr_cam.c,v 1.1.2.3 2002/11/11 13:19:10 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amr_cam.c,v 1.11 2008/05/18 20:30:23 pavalos Exp $ + * $FreeBSD: src/sys/dev/amr/amr_cam.c,v 1.28 2008/11/03 00:53:54 scottl Exp $ */ #include #include #include #include +#include -#include "amr_compat.h" +#include #include #include -#include -#include #include #include @@ -77,550 +76,548 @@ #include #include -#include "amrreg.h" -#include "amrvar.h" +#include +#include -static void amr_cam_action(struct cam_sim *sim, union ccb *ccb); -static void amr_cam_poll(struct cam_sim *sim); -static void amr_cam_complete(struct amr_command *ac); -static void amr_cam_complete_extcdb(struct amr_command *ac); +static int amr_cam_probe(device_t dev); +static int amr_cam_attach(device_t dev); +static int amr_cam_detach(device_t dev); +static void amr_cam_action(struct cam_sim *sim, union ccb *ccb); +static void amr_cam_poll(struct cam_sim *sim); +static void amr_cam_complete(struct amr_command *ac); +static int amr_cam_command(struct amr_softc *sc, struct amr_command **acp); +static devclass_t amr_pass_devclass; -/******************************************************************************** +static device_method_t amr_pass_methods[] = { + DEVMETHOD(device_probe, amr_cam_probe), + DEVMETHOD(device_attach, amr_cam_attach), + DEVMETHOD(device_detach, amr_cam_detach), + { 0, 0 } +}; + +static driver_t amr_pass_driver = { + "amrp", + amr_pass_methods, + 0 +}; + +DRIVER_MODULE(amrp, amr, amr_pass_driver, amr_pass_devclass, 0, 0); +MODULE_DEPEND(amrp, cam, 1, 1, 1); + +MALLOC_DEFINE(M_AMRCAM, "amrcam", "AMR CAM memory"); + +/*********************************************************************** * Enqueue/dequeue functions */ static __inline void amr_enqueue_ccb(struct amr_softc *sc, union ccb *ccb) { - crit_enter(); - TAILQ_INSERT_TAIL(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); - crit_exit(); + + TAILQ_INSERT_TAIL(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); } static __inline void amr_requeue_ccb(struct amr_softc *sc, union ccb *ccb) { - crit_enter(); - TAILQ_INSERT_HEAD(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); - crit_exit(); + + TAILQ_INSERT_HEAD(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); } static __inline union ccb * amr_dequeue_ccb(struct amr_softc *sc) { - union ccb *ccb; + union ccb *ccb; - crit_enter(); - if ((ccb = (union ccb *)TAILQ_FIRST(&sc->amr_cam_ccbq)) != NULL) - TAILQ_REMOVE(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); - crit_exit(); - return(ccb); + if ((ccb = (union ccb *)TAILQ_FIRST(&sc->amr_cam_ccbq)) != NULL) + TAILQ_REMOVE(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); + return(ccb); +} + +static int +amr_cam_probe(device_t dev) +{ + return (0); } /******************************************************************************** * Attach our 'real' SCSI channels to CAM */ -int -amr_cam_attach(struct amr_softc *sc) +static int +amr_cam_attach(device_t dev) { - struct cam_devq *devq; - int chn; - - /* initialise the ccb queue */ - TAILQ_INIT(&sc->amr_cam_ccbq); - - /* - * Allocate a devq for all our channels combined. This should - * allow for the maximum number of SCSI commands we will accept - * at one time. - */ - if ((devq = cam_simq_alloc(AMR_MAX_SCSI_CMDS)) == NULL) - return(ENOMEM); - - /* - * Iterate over our channels, registering them with CAM - */ - for (chn = 0; chn < sc->amr_maxchan; chn++) { - - /* allocate a sim */ - if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action, - amr_cam_poll, - "amr", - sc, - device_get_unit(sc->amr_dev), - &sim_mplock, - 1, - AMR_MAX_SCSI_CMDS, - devq)) == NULL) { - device_printf(sc->amr_dev, "CAM SIM attach failed\n"); - return(ENOMEM); - } + struct amr_softc *sc; + struct cam_devq *devq; + int chn, error; - /* register the bus ID so we can get it later */ - if (xpt_bus_register(sc->amr_cam_sim[chn], chn)) { - device_printf(sc->amr_dev, "CAM XPT bus registration failed\n"); - return(ENXIO); + sc = device_get_softc(dev); + + /* initialise the ccb queue */ + TAILQ_INIT(&sc->amr_cam_ccbq); + + /* + * Allocate a devq for all our channels combined. This should + * allow for the maximum number of SCSI commands we will accept + * at one time. Save the pointer in the softc so we can find it later + * during detach. + */ + if ((devq = cam_simq_alloc(AMR_MAX_SCSI_CMDS)) == NULL) + return(ENOMEM); + sc->amr_cam_devq = devq; + + /* + * Iterate over our channels, registering them with CAM + */ + for (chn = 0; chn < sc->amr_maxchan; chn++) { + + /* allocate a sim */ + if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action, + amr_cam_poll, "amr", sc, device_get_unit(sc->amr_dev), + &sc->amr_list_lock, 1, AMR_MAX_SCSI_CMDS, devq)) == NULL) { + device_printf(sc->amr_dev, "CAM SIM attach failed\n"); + return(ENOMEM); + } + + /* register the bus ID so we can get it later */ + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + error = xpt_bus_register(sc->amr_cam_sim[chn], chn); + lockmgr(&sc->amr_list_lock, LK_RELEASE); + if (error) { + device_printf(sc->amr_dev, + "CAM XPT bus registration failed\n"); + return(ENXIO); + } } - } - cam_simq_release(devq); - /* - * XXX we should scan the config and work out which devices are actually - * protected. - */ - return(0); + /* + * XXX we should scan the config and work out which devices are + * actually protected. + */ + sc->amr_cam_command = amr_cam_command; + return(0); } /******************************************************************************** * Disconnect ourselves from CAM */ -void -amr_cam_detach(struct amr_softc *sc) +static int +amr_cam_detach(device_t dev) { - int chn; - - /* - * If a sim was allocated for a channel, free it - */ - for (chn = 0; chn < sc->amr_maxchan; chn++) { - if (sc->amr_cam_sim[chn] != NULL) { - xpt_bus_deregister(cam_sim_path(sc->amr_cam_sim[chn])); - cam_sim_free(sc->amr_cam_sim[chn]); + struct amr_softc *sc; + int chn; + + sc = device_get_softc(dev); + lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); + for (chn = 0; chn < sc->amr_maxchan; chn++) { + /* + * If a sim was allocated for this channel, free it + */ + if (sc->amr_cam_sim[chn] != NULL) { + xpt_bus_deregister(cam_sim_path(sc->amr_cam_sim[chn])); + cam_sim_free(sc->amr_cam_sim[chn]); + } } - } + lockmgr(&sc->amr_list_lock, LK_RELEASE); + + return (0); } -/******************************************************************************** - ******************************************************************************** - CAM passthrough interface - ******************************************************************************** - ********************************************************************************/ +/*********************************************************************** + *********************************************************************** + CAM passthrough interface + *********************************************************************** + ***********************************************************************/ -/******************************************************************************** +/*********************************************************************** * Handle a request for action from CAM */ static void amr_cam_action(struct cam_sim *sim, union ccb *ccb) { - struct amr_softc *sc = cam_sim_softc(sim); - - switch(ccb->ccb_h.func_code) { - - /* - * Perform SCSI I/O to a physical device. - */ - case XPT_SCSI_IO: - { - struct ccb_hdr *ccbh = &ccb->ccb_h; - struct ccb_scsiio *csio = &ccb->csio; - - /* Validate the CCB */ - ccbh->status = CAM_REQ_INPROG; - - /* check the CDB length */ - if (csio->cdb_len > AMR_MAX_EXTCDB_LEN) - ccbh->status = CAM_REQ_CMP_ERR; - - if ((csio->cdb_len > AMR_MAX_CDB_LEN) && (sc->support_ext_cdb == 0 )) - ccbh->status = CAM_REQ_CMP_ERR; - - /* check that the CDB pointer is not to a physical address */ - if ((ccbh->flags & CAM_CDB_POINTER) && (ccbh->flags & CAM_CDB_PHYS)) - ccbh->status = CAM_REQ_CMP_ERR; - - /* if there is data transfer, it must be to/from a virtual address */ - if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { - if (ccbh->flags & CAM_DATA_PHYS) /* we can't map it */ - ccbh->status = CAM_REQ_CMP_ERR; - if (ccbh->flags & CAM_SCATTER_VALID) /* we want to do the s/g setup */ - ccbh->status = CAM_REQ_CMP_ERR; + struct amr_softc *sc = cam_sim_softc(sim); + + switch(ccb->ccb_h.func_code) { + + /* + * Perform SCSI I/O to a physical device. + */ + case XPT_SCSI_IO: + { + struct ccb_hdr *ccbh = &ccb->ccb_h; + struct ccb_scsiio *csio = &ccb->csio; + + /* Validate the CCB */ + ccbh->status = CAM_REQ_INPROG; + + /* check the CDB length */ + if (csio->cdb_len > AMR_MAX_EXTCDB_LEN) + ccbh->status = CAM_REQ_INVALID; + + if ((csio->cdb_len > AMR_MAX_CDB_LEN) && + (sc->support_ext_cdb == 0)) + ccbh->status = CAM_REQ_INVALID; + + /* check that the CDB pointer is not to a physical address */ + if ((ccbh->flags & CAM_CDB_POINTER) && + (ccbh->flags & CAM_CDB_PHYS)) + ccbh->status = CAM_REQ_INVALID; + /* + * if there is data transfer, it must be to/from a virtual + * address + */ + if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { + if (ccbh->flags & CAM_DATA_PHYS) + /* we can't map it */ + ccbh->status = CAM_REQ_INVALID; + if (ccbh->flags & CAM_SCATTER_VALID) + /* we want to do the s/g setup */ + ccbh->status = CAM_REQ_INVALID; + } + + /* + * If the command is to a LUN other than 0, fail it. + * This is probably incorrect, but during testing the + * firmware did not seem to respect the LUN field, and thus + * devices appear echoed. + */ + if (csio->ccb_h.target_lun != 0) + ccbh->status = CAM_DEV_NOT_THERE; + + /* if we're happy with the request, queue it for attention */ + if (ccbh->status == CAM_REQ_INPROG) { + + /* save the channel number in the ccb */ + csio->ccb_h.sim_priv.entries[0].field= cam_sim_bus(sim); + + amr_enqueue_ccb(sc, ccb); + amr_startio(sc); + return; + } + break; + } + + case XPT_CALC_GEOMETRY: + { + cam_calc_geometry(&ccb->ccg, /*extended*/1); + break; } /* - * If the command is to a LUN other than 0, fail it. - * This is probably incorrect, but during testing the firmware did not - * seem to respect the LUN field, and thus devices appear echoed. + * Return path stats. Some of these should probably be amended. */ - if (csio->ccb_h.target_lun != 0) - ccbh->status = CAM_REQ_CMP_ERR; + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = & ccb->cpi; + + debug(3, "XPT_PATH_INQ"); + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; + cpi->target_sprt = 0; + cpi->hba_misc = PIM_NOBUSRESET|PIM_SEQSCAN; + cpi->hba_eng_cnt = 0; + cpi->max_target = AMR_MAX_TARGETS; + cpi->max_lun = 0 /* AMR_MAX_LUNS*/; + cpi->initiator_id = 7; /* XXX variable? */ + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "LSI", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->bus_id = cam_sim_bus(sim); + cpi->base_transfer_speed = 132 * 1024; /* XXX */ + cpi->transport = XPORT_SPI; + cpi->transport_version = 2; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_2; + cpi->ccb_h.status = CAM_REQ_CMP; - /* if we're happy with the request, queue it for attention */ - if (ccbh->status == CAM_REQ_INPROG) { + break; + } - /* save the channel number in the ccb */ - csio->ccb_h.sim_priv.entries[0].field = cam_sim_bus(sim); + case XPT_RESET_BUS: + { + struct ccb_pathinq *cpi = & ccb->cpi; - amr_enqueue_ccb(sc, ccb); - amr_startio(sc); - return; + debug(1, "XPT_RESET_BUS"); + cpi->ccb_h.status = CAM_REQ_CMP; + break; } - break; - } - case XPT_CALC_GEOMETRY: - { - struct ccb_calc_geometry *ccg = &ccb->ccg; - u_int32_t size_in_mb; - u_int32_t secs_per_cylinder; + case XPT_RESET_DEV: + { + debug(1, "XPT_RESET_DEV"); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } - size_in_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size); + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts = &(ccb->cts); - if (size_in_mb > 1024) { - ccg->heads = 255; - ccg->secs_per_track = 63; - } else { - ccg->heads = 64; - ccg->secs_per_track = 32; + debug(3, "XPT_GET_TRAN_SETTINGS"); + + struct ccb_trans_settings_scsi *scsi; + struct ccb_trans_settings_spi *spi; + + scsi = &cts->proto_specific.scsi; + spi = &cts->xport_specific.spi; + + cts->protocol = PROTO_SCSI; + cts->protocol_version = SCSI_REV_2; + cts->transport = XPORT_SPI; + cts->transport_version = 2; + + if (cts->type == CTS_TYPE_USER_SETTINGS) { + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + break; + } + + spi->flags = CTS_SPI_FLAGS_DISC_ENB; + spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; + spi->sync_period = 6; /* 40MHz how wide is this bus? */ + spi->sync_offset = 31; /* How to extract this from board? */ + + spi->valid = CTS_SPI_VALID_SYNC_RATE + | CTS_SPI_VALID_SYNC_OFFSET + | CTS_SPI_VALID_BUS_WIDTH + | CTS_SPI_VALID_DISC; + scsi->valid = CTS_SCSI_VALID_TQ; + ccb->ccb_h.status = CAM_REQ_CMP; + break; } - secs_per_cylinder = ccg->heads * ccg->secs_per_track; - ccg->cylinders = ccg->volume_size / secs_per_cylinder; - ccb->ccb_h.status = CAM_REQ_CMP; - break; - } - - /* - * Return path stats. Some of these should probably be - * amended. - */ - case XPT_PATH_INQ: - { - struct ccb_pathinq *cpi = & ccb->cpi; - - debug(3, "XPT_PATH_INQ"); - cpi->version_num = 1; /* XXX??? */ - cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; - cpi->target_sprt = 0; - cpi->hba_misc = PIM_NOBUSRESET; - cpi->hba_eng_cnt = 0; - cpi->max_target = AMR_MAX_TARGETS; - cpi->max_lun = 0 /* AMR_MAX_LUNS*/; - cpi->initiator_id = 7; /* XXX variable? */ - strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); - strncpy(cpi->hba_vid, "LSI", HBA_IDLEN); - strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); - cpi->unit_number = cam_sim_unit(sim); - cpi->bus_id = cam_sim_bus(sim); - cpi->base_transfer_speed = 132 * 1024; /* XXX get from controller? */ - cpi->transport = XPORT_SPI; - cpi->transport_version = 2; - cpi->protocol = PROTO_SCSI; - cpi->protocol_version = SCSI_REV_2; - cpi->ccb_h.status = CAM_REQ_CMP; - - break; - } - - case XPT_RESET_BUS: - { - struct ccb_pathinq *cpi = & ccb->cpi; - - debug(1, "XPT_RESET_BUS"); - cpi->ccb_h.status = CAM_REQ_CMP; - break; - } - - case XPT_RESET_DEV: - { - debug(1, "XPT_RESET_DEV"); - ccb->ccb_h.status = CAM_REQ_CMP; - break; - } - - case XPT_GET_TRAN_SETTINGS: - { - struct ccb_trans_settings *cts = &(ccb->cts); - - debug(3, "XPT_GET_TRAN_SETTINGS"); - - struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; - struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; - - cts->protocol = PROTO_SCSI; - cts->protocol_version = SCSI_REV_2; - cts->transport = XPORT_SPI; - cts->transport_version = 2; - - if (cts->type == CTS_TYPE_USER_SETTINGS) { + + case XPT_SET_TRAN_SETTINGS: + debug(3, "XPT_SET_TRAN_SETTINGS"); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; break; + + + /* + * Reject anything else as unsupported. + */ + default: + /* we can't do this */ + ccb->ccb_h.status = CAM_REQ_INVALID; + break; } - spi->flags = CTS_SPI_FLAGS_DISC_ENB; - spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; - spi->sync_period = 6; /* 40MHz how wide is this bus? */ - spi->sync_offset = 31; /* How to extract this from board? */ - - spi->valid = CTS_SPI_VALID_SYNC_RATE - | CTS_SPI_VALID_SYNC_OFFSET - | CTS_SPI_VALID_BUS_WIDTH - | CTS_SPI_VALID_DISC; - scsi->valid = CTS_SCSI_VALID_TQ; - ccb->ccb_h.status = CAM_REQ_CMP; - break; - } - - case XPT_SET_TRAN_SETTINGS: - debug(3, "XPT_SET_TRAN_SETTINGS"); - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - break; - - - /* - * Reject anything else as unsupported. - */ - default: - /* we can't do this */ - ccb->ccb_h.status = CAM_REQ_INVALID; - break; - } - xpt_done(ccb); + KKASSERT(lockstatus(&sc->amr_list_lock, curthread) != 0); + xpt_done(ccb); } -/******************************************************************************** - * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI command. +/*********************************************************************** + * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI + * command. */ -int +static int amr_cam_command(struct amr_softc *sc, struct amr_command **acp) { - struct amr_command *ac; - struct amr_passthrough *ap; - struct amr_ext_passthrough *aep; - struct ccb_scsiio *csio; - int bus, target, error; - - error = 0; - ac = NULL; - ap = NULL; - aep = NULL; - - /* check to see if there is a ccb for us to work with */ - if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL) - goto out; - - /* get bus/target, XXX validate against protected devices? */ - bus = csio->ccb_h.sim_priv.entries[0].field; - target = csio->ccb_h.target_id; - - /* - * Build a passthrough command. - */ - - /* construct passthrough */ - if (sc->support_ext_cdb ) { - aep = kmalloc(sizeof(*aep), M_DEVBUF, M_INTWAIT | M_ZERO); - aep->ap_timeout = 2; - aep->ap_ars = 1; - aep->ap_request_sense_length = 14; - aep->ap_islogical = 0; - aep->ap_channel = bus; - aep->ap_scsi_id = target; - aep->ap_logical_drive_no = csio->ccb_h.target_lun; - aep->ap_cdb_length = csio->cdb_len; - aep->ap_data_transfer_length = csio->dxfer_len; - if (csio->ccb_h.flags & CAM_CDB_POINTER) { - bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len); - } else { - bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb, csio->cdb_len); - } - /* we leave the data s/g list and s/g count to the map routine later */ - - debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0], aep->ap_cdb_length, csio->dxfer_len, - aep->ap_channel, aep->ap_scsi_id, aep->ap_logical_drive_no); - - } else { - ap = kmalloc(sizeof(*ap), M_DEVBUF, M_INTWAIT | M_ZERO); - ap->ap_timeout = 0; - ap->ap_ars = 1; - ap->ap_request_sense_length = 14; - ap->ap_islogical = 0; - ap->ap_channel = bus; - ap->ap_scsi_id = target; - ap->ap_logical_drive_no = csio->ccb_h.target_lun; - ap->ap_cdb_length = csio->cdb_len; - ap->ap_data_transfer_length = csio->dxfer_len; - if (csio->ccb_h.flags & CAM_CDB_POINTER) { - bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len); - } else { - bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb, csio->cdb_len); - } - /* we leave the data s/g list and s/g count to the map routine later */ - - debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0], ap->ap_cdb_length, csio->dxfer_len, - ap->ap_channel, ap->ap_scsi_id, ap->ap_logical_drive_no); - } - - /* construct command */ - if ((ac = amr_alloccmd(sc)) == NULL) { - error = ENOMEM; + struct amr_command *ac; + struct amr_passthrough *ap; + struct amr_ext_passthrough *aep; + struct ccb_scsiio *csio; + int bus, target, error; + + error = 0; + ac = NULL; + ap = NULL; + aep = NULL; + + /* check to see if there is a ccb for us to work with */ + if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL) goto out; - } - - ac->ac_flags |= AMR_CMD_DATAOUT; - - ac->ac_ccb_data = csio->data_ptr; - ac->ac_ccb_length = csio->dxfer_len; - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - ac->ac_flags |= AMR_CMD_CCB_DATAIN; - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) - ac->ac_flags |= AMR_CMD_CCB_DATAOUT; - - ac->ac_private = csio; - if ( sc->support_ext_cdb ) { - ac->ac_data = aep; - ac->ac_length = sizeof(*aep); - ac->ac_complete = amr_cam_complete_extcdb; - ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS; - } else { - ac->ac_data = ap; - ac->ac_length = sizeof(*ap); - ac->ac_complete = amr_cam_complete; - ac->ac_mailbox.mb_command = AMR_CMD_PASS; - } -out: - if (error != 0) { - if (ac != NULL) - amr_releasecmd(ac); - if (ap != NULL) - kfree(ap, M_DEVBUF); - if (aep != NULL) - kfree(aep, M_DEVBUF); - if (csio != NULL) /* put it back and try again later */ - amr_requeue_ccb(sc, (union ccb *)csio); - } - *acp = ac; - return(error); -} - -/******************************************************************************** - * Check for interrupt status - */ -static void -amr_cam_poll(struct cam_sim *sim) -{ - amr_done(cam_sim_softc(sim)); -} + /* get bus/target, XXX validate against protected devices? */ + bus = csio->ccb_h.sim_priv.entries[0].field; + target = csio->ccb_h.target_id; - /******************************************************************************** - * Handle completion of a command submitted via CAM. - */ -static void -amr_cam_complete(struct amr_command *ac) -{ - struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data; - struct ccb_scsiio *csio = (struct ccb_scsiio *)ac->ac_private; - struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr; - - /* XXX note that we're ignoring ac->ac_status - good idea? */ + /* + * Build a passthrough command. + */ - debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, ap->ap_scsi_status); + /* construct command */ + if ((ac = amr_alloccmd(sc)) == NULL) { + error = ENOMEM; + goto out; + } - /* - * Hide disks from CAM so that they're not picked up and treated as 'normal' disks. - * - * If the configuration provides a mechanism to mark a disk a "not managed", we - * could add handling for that to allow disks to be selectively visible. - */ + /* construct passthrough */ + if (sc->support_ext_cdb ) { + aep = &ac->ac_ccb->ccb_epthru; + aep->ap_timeout = 2; + aep->ap_ars = 1; + aep->ap_request_sense_length = 14; + aep->ap_islogical = 0; + aep->ap_channel = bus; + aep->ap_scsi_id = target; + aep->ap_logical_drive_no = csio->ccb_h.target_lun; + aep->ap_cdb_length = csio->cdb_len; + aep->ap_data_transfer_length = csio->dxfer_len; + if (csio->ccb_h.flags & CAM_CDB_POINTER) { + bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len); + } else { + bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb, + csio->cdb_len); + } + /* + * we leave the data s/g list and s/g count to the map routine + * later + */ + + debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0], + aep->ap_cdb_length, csio->dxfer_len, aep->ap_channel, + aep->ap_scsi_id, aep->ap_logical_drive_no); - if ((ap->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) { - bzero(csio->data_ptr, csio->dxfer_len); - if (ap->ap_scsi_status == 0xf0) { - csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; } else { - csio->ccb_h.status = CAM_DEV_NOT_THERE; + ap = &ac->ac_ccb->ccb_pthru; + ap->ap_timeout = 0; + ap->ap_ars = 1; + ap->ap_request_sense_length = 14; + ap->ap_islogical = 0; + ap->ap_channel = bus; + ap->ap_scsi_id = target; + ap->ap_logical_drive_no = csio->ccb_h.target_lun; + ap->ap_cdb_length = csio->cdb_len; + ap->ap_data_transfer_length = csio->dxfer_len; + if (csio->ccb_h.flags & CAM_CDB_POINTER) { + bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len); + } else { + bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb, + csio->cdb_len); + } + /* + * we leave the data s/g list and s/g count to the map routine + * later + */ + + debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0], + ap->ap_cdb_length, csio->dxfer_len, ap->ap_channel, + ap->ap_scsi_id, ap->ap_logical_drive_no); } - } else { - /* handle passthrough SCSI status */ - switch(ap->ap_scsi_status) { - case 0: /* completed OK */ - csio->ccb_h.status = CAM_REQ_CMP; - break; + ac->ac_flags |= AMR_CMD_CCB; - case 0x02: - csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; - csio->scsi_status = SCSI_STATUS_CHECK_COND; - bcopy(ap->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN); - csio->sense_len = AMR_MAX_REQ_SENSE_LEN; - csio->ccb_h.status |= CAM_AUTOSNS_VALID; - break; + ac->ac_data = csio->data_ptr; + ac->ac_length = csio->dxfer_len; + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + ac->ac_flags |= AMR_CMD_DATAIN; + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + ac->ac_flags |= AMR_CMD_DATAOUT; - case 0x08: - csio->ccb_h.status = CAM_SCSI_BUSY; - break; + ac->ac_private = csio; + ac->ac_complete = amr_cam_complete; + if ( sc->support_ext_cdb ) { + ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS; + } else { + ac->ac_mailbox.mb_command = AMR_CMD_PASS; + } - case 0xf0: - case 0xf4: - default: - csio->ccb_h.status = CAM_REQ_CMP_ERR; - break; +out: + if (error != 0) { + if (ac != NULL) + amr_releasecmd(ac); + if (csio != NULL) + /* put it back and try again later */ + amr_requeue_ccb(sc, (union ccb *)csio); } - } - kfree(ap, M_DEVBUF); - if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) - debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " "); - xpt_done((union ccb *)csio); - amr_releasecmd(ac); + *acp = ac; + return(error); } -/******************************************************************************** - * Handle completion of a command submitted via CAM. - * Completion for extended cdb +/*********************************************************************** + * Check for interrupt status */ static void -amr_cam_complete_extcdb(struct amr_command *ac) +amr_cam_poll(struct cam_sim *sim) { - struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data; - struct ccb_scsiio *csio = (struct ccb_scsiio *)ac->ac_private; - struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr; - - /* XXX note that we're ignoring ac->ac_status - good idea? */ - - debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status); - /* - * Hide disks from CAM so that they're not picked up and treated as 'normal' disks. - * - * If the configuration provides a mechanism to mark a disk a "not managed", we - * could add handling for that to allow disks to be selectively visible. - */ + amr_done(cam_sim_softc(sim)); +} - if ((aep->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) { - bzero(csio->data_ptr, csio->dxfer_len); - if (aep->ap_scsi_status == 0xf0) { - csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; - } else { - csio->ccb_h.status = CAM_DEV_NOT_THERE; + /********************************************************************** + * Handle completion of a command submitted via CAM. + */ +static void +amr_cam_complete(struct amr_command *ac) +{ + struct amr_passthrough *ap; + struct amr_ext_passthrough *aep; + struct ccb_scsiio *csio; + struct scsi_inquiry_data *inq; + int scsi_status, cdb0; + + ap = &ac->ac_ccb->ccb_pthru; + aep = &ac->ac_ccb->ccb_epthru; + csio = (struct ccb_scsiio *)ac->ac_private; + inq = (struct scsi_inquiry_data *)csio->data_ptr; + + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) + scsi_status = aep->ap_scsi_status; + else + scsi_status = ap->ap_scsi_status; + debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status, + scsi_status); + + /* Make sure the status is sane */ + if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) { + csio->ccb_h.status = CAM_REQ_CMP_ERR; + goto out; } - } else { + + /* + * Hide disks from CAM so that they're not picked up and treated as + * 'normal' disks. + * + * If the configuration provides a mechanism to mark a disk a "not + * managed", we could add handling for that to allow disks to be + * selectively visible. + */ /* handle passthrough SCSI status */ - switch(aep->ap_scsi_status) { - case 0: /* completed OK */ - csio->ccb_h.status = CAM_REQ_CMP; - break; + switch(scsi_status) { + case 0: /* completed OK */ + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) + cdb0 = aep->ap_cdb[0]; + else + cdb0 = ap->ap_cdb[0]; + if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) + inq->device = (inq->device & 0xe0) | T_NODEVICE; + csio->ccb_h.status = CAM_REQ_CMP; + break; case 0x02: - csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; - csio->scsi_status = SCSI_STATUS_CHECK_COND; - bcopy(aep->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN); - csio->sense_len = AMR_MAX_REQ_SENSE_LEN; - csio->ccb_h.status |= CAM_AUTOSNS_VALID; - break; + csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; + csio->scsi_status = SCSI_STATUS_CHECK_COND; + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) + bcopy(aep->ap_request_sense_area, &csio->sense_data, + AMR_MAX_REQ_SENSE_LEN); + else + bcopy(ap->ap_request_sense_area, &csio->sense_data, + AMR_MAX_REQ_SENSE_LEN); + csio->sense_len = AMR_MAX_REQ_SENSE_LEN; + csio->ccb_h.status |= CAM_AUTOSNS_VALID; + break; case 0x08: - csio->ccb_h.status = CAM_SCSI_BUSY; - break; + csio->ccb_h.status = CAM_SCSI_BUSY; + break; case 0xf0: case 0xf4: default: - csio->ccb_h.status = CAM_REQ_CMP_ERR; - break; + /* + * Non-zero LUNs are already filtered, so there's no need + * to return CAM_DEV_NOT_THERE. + */ + csio->ccb_h.status = CAM_SEL_TIMEOUT; + break; } - } - kfree(aep, M_DEVBUF); - if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) - debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " "); - xpt_done((union ccb *)csio); - amr_releasecmd(ac); + +out: + if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) + debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, + " "); + + lockmgr(&ac->ac_sc->amr_list_lock, LK_EXCLUSIVE); + xpt_done((union ccb *)csio); + amr_releasecmd(ac); + lockmgr(&ac->ac_sc->amr_list_lock, LK_RELEASE); } diff --git a/sys/dev/raid/amr/amr_cam/Makefile b/sys/dev/raid/amr/amr_cam/Makefile new file mode 100644 index 0000000000..cdd3396ebd --- /dev/null +++ b/sys/dev/raid/amr/amr_cam/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD: src/sys/modules/amr/amr_cam/Makefile,v 1.1 2008/11/03 04:13:27 scottl Exp $ + +.PATH: ${.CURDIR}/.. + +KMOD= amr_cam +SRCS= amr_cam.c device_if.h bus_if.h +SRCS+= opt_cam.h opt_scsi.h + +.include diff --git a/sys/dev/raid/amr/amr_compat.h b/sys/dev/raid/amr/amr_compat.h deleted file mode 100644 index 88e3f861a0..0000000000 --- a/sys/dev/raid/amr/amr_compat.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * Copyright (c) 2000 Michael Smith - * Copyright (c) 2000 BSDi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Copyright (c) 2002 Eric Moore - * Copyright (c) 2002 LSI Logic Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The party using or redistributing the source code and binary forms - * agrees to the disclaimer below and the terms and conditions set forth - * herein. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/amr/amr_compat.h,v 1.2.2.4 2002/11/11 13:19:10 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amr_compat.h,v 1.7 2006/02/17 19:18:05 dillon Exp $ - */ - -#include -#include -#include -#include - -#ifndef __packed -#define __packed __attribute__ ((packed)) -#endif diff --git a/sys/dev/raid/amr/amr_disk.c b/sys/dev/raid/amr/amr_disk.c index 999c0eae51..a1df430d97 100644 --- a/sys/dev/raid/amr/amr_disk.c +++ b/sys/dev/raid/amr/amr_disk.c @@ -24,7 +24,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + */ +/*- * Copyright (c) 2002 Eric Moore * Copyright (c) 2002 LSI Logic Corporation * All rights reserved. @@ -53,7 +54,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amr_disk.c,v 1.5.2.5 2002/12/20 15:12:04 emoore Exp $ + * $FreeBSD: src/sys/dev/amr/amr_disk.c,v 1.39 2006/10/31 21:19:25 pjd Exp $ */ /* @@ -63,24 +64,19 @@ #include #include #include +#include -#include "amr_compat.h" +#include #include #include -#include -#include #include -#include -#include -#include - -#include +#include -#include "amrio.h" -#include "amrreg.h" -#include "amrvar.h" -#include "amr_tables.h" +#include +#include +#include +#include /* prototypes */ static int amrd_probe(device_t dev); @@ -88,23 +84,20 @@ static int amrd_attach(device_t dev); static int amrd_detach(device_t dev); static d_open_t amrd_open; -static d_close_t amrd_close; static d_strategy_t amrd_strategy; -static d_ioctl_t amrd_ioctl; static d_dump_t amrd_dump; static struct dev_ops amrd_ops = { { "amrd", 0, D_DISK }, .d_open = amrd_open, - .d_close = amrd_close, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = amrd_ioctl, .d_strategy = amrd_strategy, - .d_dump = amrd_dump + .d_dump = amrd_dump, }; static devclass_t amrd_devclass; +#ifdef FREEBSD_4 +int amr_disks_registered = 0; +#endif static device_method_t amrd_methods[] = { DEVMETHOD(device_probe, amrd_probe), @@ -124,8 +117,7 @@ DRIVER_MODULE(amrd, amr, amrd_driver, amrd_devclass, 0, 0); static int amrd_open(struct dev_open_args *ap) { - cdev_t dev = ap->a_head.a_dev; - struct amrd_softc *sc = (struct amrd_softc *)dev->si_drv1; + struct amrd_softc *sc = ap->a_head.a_dev->si_drv1; debug_called(1); @@ -135,73 +127,38 @@ amrd_open(struct dev_open_args *ap) /* controller not active? */ if (sc->amrd_controller->amr_state & AMR_STATE_SHUTDOWN) return(ENXIO); -#if 0 - bzero(&info, sizeof(info)); - info.d_media_blksize = AMR_BLKSIZE; /* optional */ - info.d_media_blocks = sc->amrd_drive->al_size; - info.d_type = DTYPE_SCSI; /* mandatory */ - info.d_secpertrack = sc->amrd_drive->al_sectors; - info.d_nheads = sc->amrd_drive->al_heads; - info.d_ncylinders = sc->amrd_drive->al_cylinders; - info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads; - - disk_setdiskinfo(&sc->amrd_disk, &info); -#endif - sc->amrd_flags |= AMRD_OPEN; return (0); } - -static int -amrd_close(struct dev_close_args *ap) -{ - cdev_t dev = ap->a_head.a_dev; - struct amrd_softc *sc = (struct amrd_softc *)dev->si_drv1; - - debug_called(1); - - if (sc == NULL) - return (ENXIO); - sc->amrd_flags &= ~AMRD_OPEN; - return (0); -} - -static int -amrd_ioctl(struct dev_ioctl_args *ap) -{ - return (ENOTTY); -} - - /******************************************************************************** * System crashdump support */ -int + +static int amrd_dump(struct dev_dump_args *ap) { cdev_t dev = ap->a_head.a_dev; - struct amrd_softc *amrd_sc = (struct amrd_softc *)dev->si_drv1; + off_t offset = ap->a_offset; + void *virtual = ap->a_virtual; + size_t length = ap->a_length; + struct amrd_softc *amrd_sc; struct amr_softc *amr_sc; - int error = 0; - int driveno; + int error; - debug_called(1); - - amr_sc = (struct amr_softc *)amrd_sc->amrd_controller; - - if (!amrd_sc || !amr_sc) + amrd_sc = (struct amrd_softc *)dev->si_drv1; + if (amrd_sc == NULL) return(ENXIO); + amr_sc = (struct amr_softc *)amrd_sc->amrd_controller; - driveno = amrd_sc->amrd_drive - amr_sc->amr_drive; - - if (ap->a_length > 0) { - if ((error = amr_dump_blocks(amr_sc,driveno,ap->a_offset / AMR_BLKSIZE, - (void *)ap->a_virtual,(int) ap->a_length / AMR_BLKSIZE )) != 0) + if (length > 0) { + int driveno = amrd_sc->amrd_drive - amr_sc->amr_drive; + if ((error = amr_dump_blocks(amr_sc,driveno,offset / AMR_BLKSIZE ,(void *)virtual,(int) length / AMR_BLKSIZE )) != 0) return(error); + } return(0); - } + /* * Read/write routine for a buffer. Finds the proper unit, range checks * arguments, and schedules the transfer. Does not wait for the transfer @@ -225,7 +182,7 @@ amrd_strategy(struct dev_strategy_args *ap) devstat_start_transaction(&sc->amrd_stats); amr_submit_bio(sc->amrd_controller, bio); - return(0); + return (0); bad: bp->b_flags |= B_ERROR; @@ -235,12 +192,13 @@ amrd_strategy(struct dev_strategy_args *ap) */ bp->b_resid = bp->b_bcount; biodone(bio); - return(0); + return (0); } void -amrd_intr(struct bio *bio) +amrd_intr(void *data) { + struct bio *bio = (struct bio *)data; struct buf *bp = bio->bio_buf; debug_called(2); @@ -251,6 +209,7 @@ amrd_intr(struct bio *bio) } else { bp->b_resid = 0; } + biodone(bio); } @@ -267,10 +226,10 @@ amrd_probe(device_t dev) static int amrd_attach(device_t dev) { - struct disk_info info; struct amrd_softc *sc = (struct amrd_softc *)device_get_softc(dev); device_t parent; - + struct disk_info info; + debug_called(1); parent = device_get_parent(dev); @@ -295,19 +254,19 @@ amrd_attach(device_t dev) /* set maximum I/O size to match the maximum s/g size */ sc->amrd_dev_t->si_iosize_max = (AMR_NSEG - 1) * PAGE_SIZE; - /* - * Set disk info, as it appears that all needed data is available already. - * Setting the disk info will also cause the probing to start. - */ - bzero(&info, sizeof(info)); + /* + * Set disk info, as it appears that all needed data is available already. + * Setting the disk info will also cause the probing to start. + */ + bzero(&info, sizeof(info)); info.d_media_blksize = AMR_BLKSIZE; /* optional */ - info.d_media_blocks = sc->amrd_drive->al_size; + info.d_media_blocks = sc->amrd_drive->al_size; - info.d_type = DTYPE_SCSI; /* mandatory */ + info.d_type = DTYPE_SCSI; /* mandatory */ info.d_secpertrack = sc->amrd_drive->al_sectors; - info.d_nheads = sc->amrd_drive->al_heads; + info.d_nheads = sc->amrd_drive->al_heads; info.d_ncylinders = sc->amrd_drive->al_cylinders; - info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads; + info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads; disk_setdiskinfo(&sc->amrd_disk, &info); @@ -321,11 +280,18 @@ amrd_detach(device_t dev) debug_called(1); - if (sc->amrd_flags & AMRD_OPEN) +#if 0 /* XXX swildner */ + if (sc->amrd_disk->d_flags & DISKFLAG_OPEN) return(EBUSY); +#endif devstat_remove_entry(&sc->amrd_stats); +#ifdef FREEBSD_4 + if (--amr_disks_registered == 0) + cdevsw_remove(&amrddisk_cdevsw); +#else disk_destroy(&sc->amrd_disk); +#endif return(0); } diff --git a/sys/dev/raid/amr/amr_linux.c b/sys/dev/raid/amr/amr_linux.c new file mode 100644 index 0000000000..362a1666a3 --- /dev/null +++ b/sys/dev/raid/amr/amr_linux.c @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2005 Paul Saab + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/amr/amr_linux.c,v 1.5 2009/05/20 17:29:21 imp Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */ +#include +#include +#else +#include +#include +#endif +#include + +/* There are multiple ioctl number ranges that need to be handled */ +#define AMR_LINUX_IOCTL_MIN 0x6d00 +#define AMR_LINUX_IOCTL_MAX 0x6d01 + +static linux_ioctl_function_t amr_linux_ioctl; +static struct linux_ioctl_handler amr_linux_handler = {amr_linux_ioctl, + AMR_LINUX_IOCTL_MIN, + AMR_LINUX_IOCTL_MAX}; + +SYSINIT (amr_register, SI_SUB_KLD, SI_ORDER_MIDDLE, + linux_ioctl_register_handler, &amr_linux_handler); +SYSUNINIT(amr_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, + linux_ioctl_unregister_handler, &amr_linux_handler); + +static int +amr_linux_modevent(module_t mod, int cmd, void *data) +{ + return (0); +} + +DEV_MODULE(amr_linux, amr_linux_modevent, NULL); +MODULE_DEPEND(amr, linux, 1, 1, 1); + +static int +amr_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + + if ((error = fget(p, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p); + fdrop(fp, p); + return (error); +} diff --git a/sys/dev/raid/amr/amr_linux/Makefile b/sys/dev/raid/amr/amr_linux/Makefile new file mode 100644 index 0000000000..ec14676e8d --- /dev/null +++ b/sys/dev/raid/amr/amr_linux/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD: src/sys/modules/amr/amr_linux/Makefile,v 1.1 2006/01/24 21:13:49 ambrisko Exp $ + +.PATH: ${.CURDIR}/.. + +KMOD= amr_linux +SRCS= amr_linux.c device_if.h bus_if.h + +.include diff --git a/sys/dev/raid/amr/amr_pci.c b/sys/dev/raid/amr/amr_pci.c index 76c060da92..0ee0937610 100644 --- a/sys/dev/raid/amr/amr_pci.c +++ b/sys/dev/raid/amr/amr_pci.c @@ -23,9 +23,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + */ +/*- * Copyright (c) 2002 Eric Moore - * Copyright (c) 2002 LSI Logic Corporation + * Copyright (c) 2002, 2004 LSI Logic Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,27 +53,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amr_pci.c,v 1.1.2.9 2002/12/20 15:12:04 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amr_pci.c,v 1.9 2006/12/22 23:26:23 swildner Exp $ + * $FreeBSD: src/sys/dev/amr/amr_pci.c,v 1.40 2007/12/12 05:55:03 scottl Exp $ */ #include #include #include +#include +#include -#include "amr_compat.h" +#include #include #include -#include -#include + #include #include #include -#include "amrio.h" -#include "amrreg.h" -#include "amrvar.h" +#include +#include +#include static int amr_pci_probe(device_t dev); static int amr_pci_attach(device_t dev); @@ -82,10 +83,16 @@ static int amr_pci_suspend(device_t dev); static int amr_pci_resume(device_t dev); static void amr_pci_intr(void *arg); static void amr_pci_free(struct amr_softc *sc); -static void amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); +static void amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); static int amr_sglist_map(struct amr_softc *sc); -static void amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); static int amr_setup_mbox(struct amr_softc *sc); +static int amr_ccb_map(struct amr_softc *sc); + +static u_int amr_force_sg32 = 0; +TUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32); +SYSCTL_DECL(_hw_amr); +SYSCTL_UINT(_hw_amr, OID_AUTO, force_sg32, CTLFLAG_RD, &amr_force_sg32, 0, + "Force the AMR driver to use 32bit scatter gather"); static device_method_t amr_methods[] = { /* Device interface */ @@ -109,46 +116,64 @@ static driver_t amr_pci_driver = { static devclass_t amr_devclass; DRIVER_MODULE(amr, pci, amr_pci_driver, amr_devclass, 0, 0); +MODULE_DEPEND(amr, pci, 1, 1, 1); +MODULE_DEPEND(amr, cam, 1, 1, 1); -static struct +static struct amr_ident { int vendor; int device; - int flag; -#define PROBE_SIGNATURE (1<<0) + int flags; +#define AMR_ID_PROBE_SIG (1<<0) /* generic i960RD, check signature */ +#define AMR_ID_DO_SG64 (1<<1) +#define AMR_ID_QUARTZ (1<<2) } amr_device_ids[] = { {0x101e, 0x9010, 0}, {0x101e, 0x9060, 0}, - {0x8086, 0x1960, PROBE_SIGNATURE},/* generic i960RD, check for signature */ - {0x101e, 0x1960, 0}, - {0x1000, 0x1960, PROBE_SIGNATURE}, - {0x1000, 0x0407, 0}, - {0x1028, 0x000e, PROBE_SIGNATURE}, /* perc4/di i960 */ - {0x1028, 0x000f, 0}, /* perc4/di Verde*/ + {0x8086, 0x1960, AMR_ID_QUARTZ | AMR_ID_PROBE_SIG}, + {0x101e, 0x1960, AMR_ID_QUARTZ}, + {0x1000, 0x1960, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, + {0x1000, 0x0407, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, + {0x1000, 0x0408, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, + {0x1000, 0x0409, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, + {0x1028, 0x000e, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, /* perc4/di i960 */ + {0x1028, 0x000f, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di Verde*/ + {0x1028, 0x0013, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di */ {0, 0, 0} }; -static int -amr_pci_probe(device_t dev) +static struct amr_ident * +amr_find_ident(device_t dev) { - int i, sig; - - debug_called(1); + struct amr_ident *id; + int sig; - for (i = 0; amr_device_ids[i].vendor != 0; i++) { - if ((pci_get_vendor(dev) == amr_device_ids[i].vendor) && - (pci_get_device(dev) == amr_device_ids[i].device)) { + for (id = amr_device_ids; id->vendor != 0; id++) { + if ((pci_get_vendor(dev) == id->vendor) && + (pci_get_device(dev) == id->device)) { /* do we need to test for a signature? */ - if (amr_device_ids[i].flag & PROBE_SIGNATURE) { + if (id->flags & AMR_ID_PROBE_SIG) { sig = pci_read_config(dev, AMR_CFG_SIG, 2); if ((sig != AMR_SIGNATURE_1) && (sig != AMR_SIGNATURE_2)) continue; } - device_set_desc(dev, "LSILogic MegaRAID"); - return(-10); /* allow room to be overridden */ + return (id); } } + return (NULL); +} + +static int +amr_pci_probe(device_t dev) +{ + + debug_called(1); + + if (amr_find_ident(dev) != NULL) { + device_set_desc(dev, LSI_DESC_PCI); + return(BUS_PROBE_DEFAULT); + } return(ENXIO); } @@ -156,6 +181,7 @@ static int amr_pci_attach(device_t dev) { struct amr_softc *sc; + struct amr_ident *id; int rid, rtype, error; u_int32_t command; @@ -174,28 +200,35 @@ amr_pci_attach(device_t dev) /* * Determine board type. */ + if ((id = amr_find_ident(dev)) == NULL) + return (ENXIO); + command = pci_read_config(dev, PCIR_COMMAND, 1); - if ((pci_get_device(dev) == 0x1960) || (pci_get_device(dev) == 0x0407) || - (pci_get_device(dev) == 0x000e) || (pci_get_device(dev) == 0x000f)) { + if (id->flags & AMR_ID_QUARTZ) { /* * Make sure we are going to be able to talk to this board. */ if ((command & PCIM_CMD_MEMEN) == 0) { device_printf(dev, "memory window not available\n"); - goto out; + return (ENXIO); } sc->amr_type |= AMR_TYPE_QUARTZ; - } else { /* * Make sure we are going to be able to talk to this board. */ if ((command & PCIM_CMD_PORTEN) == 0) { device_printf(dev, "I/O window not available\n"); - goto out; + return (ENXIO); } } + if ((amr_force_sg32 == 0) && (id->flags & AMR_ID_DO_SG64) && + (sizeof(vm_paddr_t) > 4)) { + device_printf(dev, "Using 64-bit DMA\n"); + sc->amr_type |= AMR_TYPE_SG64; + } + /* force the busmaster enable bit on */ if (!(command & PCIM_CMD_BUSMASTEREN)) { device_printf(dev, "busmaster bit not set, enabling\n"); @@ -206,9 +239,9 @@ amr_pci_attach(device_t dev) /* * Allocate the PCI register window. */ - rid = PCIR_MAPS; + rid = PCIR_BAR(0); rtype = AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT; - sc->amr_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE); + sc->amr_reg = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE); if (sc->amr_reg == NULL) { device_printf(sc->amr_dev, "can't allocate register window\n"); goto out; @@ -220,15 +253,15 @@ amr_pci_attach(device_t dev) * Allocate and connect our interrupt. */ rid = 0; - sc->amr_irq = bus_alloc_resource(sc->amr_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); + sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); if (sc->amr_irq == NULL) { device_printf(sc->amr_dev, "can't allocate interrupt\n"); goto out; } - error = bus_setup_intr(sc->amr_dev, sc->amr_irq, - 0, amr_pci_intr, sc, - &sc->amr_intr, NULL); - if (error) { + if (bus_setup_intr(sc->amr_dev, sc->amr_irq, + 0, amr_pci_intr, + sc, &sc->amr_intr, NULL)) { device_printf(sc->amr_dev, "can't set up interrupt\n"); goto out; } @@ -242,13 +275,15 @@ amr_pci_attach(device_t dev) * Allocate the parent bus DMA tag appropriate for PCI. */ if (bus_dma_tag_create(NULL, /* parent */ - 1, 0, /* alignment, boundary */ + 1, 0, /* alignment,boundary */ + AMR_IS_SG64(sc) ? + BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ &sc->amr_parent_dmat)) { device_printf(dev, "can't allocate parent DMA tag\n"); goto out; @@ -258,23 +293,38 @@ amr_pci_attach(device_t dev) * Create DMA tag for mapping buffers into controller-addressable space. */ if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ + 1, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ - BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - 0, /* flags */ + MAXBSIZE, /* maxsegsize */ + 0, /* flags */ &sc->amr_buffer_dmat)) { device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); goto out; } + if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ + 1, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ + MAXBSIZE, /* maxsegsize */ + 0, /* flags */ + &sc->amr_buffer64_dmat)) { + device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); + goto out; + } + debug(2, "dma tag done"); /* * Allocate and set up mailbox in a bus-visible fashion. */ + lockinit(&sc->amr_list_lock, "AMR List Lock", 0, LK_CANRECURSE); + lockinit(&sc->amr_hw_lock, "AMR HW Lock", 0, LK_CANRECURSE); if ((error = amr_setup_mbox(sc)) != 0) goto out; @@ -285,9 +335,13 @@ amr_pci_attach(device_t dev) */ if (amr_sglist_map(sc)) goto out; - debug(2, "s/g list mapped"); + if (amr_ccb_map(sc)) + goto out; + debug(2, "ccb mapped"); + + /* * Do bus-independant initialisation, bring controller online. */ @@ -347,7 +401,6 @@ amr_pci_shutdown(device_t dev) device_printf(sc->amr_dev, "flushing cache..."); kprintf("%s\n", amr_flush(sc) ? "failed" : "done"); - crit_enter(); error = 0; /* delete all our child devices */ @@ -362,7 +415,6 @@ amr_pci_shutdown(device_t dev) /* XXX disable interrupts? */ shutdown_out: - crit_exit(); return(error); } @@ -413,7 +465,7 @@ amr_pci_intr(void *arg) { struct amr_softc *sc = (struct amr_softc *)arg; - debug_called(2); + debug_called(3); /* collect finished commands, queue anything waiting */ amr_done(sc); @@ -427,8 +479,8 @@ amr_pci_intr(void *arg) static void amr_pci_free(struct amr_softc *sc) { - u_int8_t *p; - + void *p; + debug_called(1); amr_free(sc); @@ -436,6 +488,14 @@ amr_pci_free(struct amr_softc *sc) /* destroy data-transfer DMA tag */ if (sc->amr_buffer_dmat) bus_dma_tag_destroy(sc->amr_buffer_dmat); + if (sc->amr_buffer64_dmat) + bus_dma_tag_destroy(sc->amr_buffer64_dmat); + + /* free and destroy DMA memory and tag for passthrough pool */ + if (sc->amr_ccb) + bus_dmamem_free(sc->amr_ccb_dmat, sc->amr_ccb, sc->amr_ccb_dmamap); + if (sc->amr_ccb_dmat) + bus_dma_tag_destroy(sc->amr_ccb_dmat); /* free and destroy DMA memory and tag for s/g lists */ if (sc->amr_sgtable) @@ -444,9 +504,9 @@ amr_pci_free(struct amr_softc *sc) bus_dma_tag_destroy(sc->amr_sg_dmat); /* free and destroy DMA memory and tag for mailbox */ + p = (void *)(uintptr_t)(volatile void *)sc->amr_mailbox64; if (sc->amr_mailbox) { - p = (u_int8_t *)(uintptr_t)(volatile void *)sc->amr_mailbox; - bus_dmamem_free(sc->amr_mailbox_dmat, p - 16, sc->amr_mailbox_dmamap); + bus_dmamem_free(sc->amr_mailbox_dmat, p, sc->amr_mailbox_dmamap); } if (sc->amr_mailbox_dmat) bus_dma_tag_destroy(sc->amr_mailbox_dmat); @@ -465,27 +525,28 @@ amr_pci_free(struct amr_softc *sc) if (sc->amr_reg != NULL) bus_release_resource(sc->amr_dev, AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT, - PCIR_MAPS, sc->amr_reg); + PCIR_BAR(0), sc->amr_reg); } /******************************************************************************** * Allocate and map the scatter/gather table in bus space. */ static void -amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) +amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct amr_softc *sc = (struct amr_softc *)arg; + uint32_t *addr; debug_called(1); - /* save base of s/g table's address in bus space */ - sc->amr_sgbusaddr = segs->ds_addr; + addr = arg; + *addr = segs[0].ds_addr; } static int amr_sglist_map(struct amr_softc *sc) { size_t segsize; + void *p; int error; debug_called(1); @@ -494,12 +555,17 @@ amr_sglist_map(struct amr_softc *sc) * Create a single tag describing a region large enough to hold all of * the s/g lists we will need. * - * Note that we could probably use AMR_LIMITCMD here, but that may become tunable. + * Note that we could probably use AMR_LIMITCMD here, but that may become + * tunable. */ - segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD; + if (AMR_IS_SG64(sc)) + segsize = sizeof(struct amr_sg64entry) * AMR_NSEG * AMR_MAXCMD; + else + segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD; + error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ + 512, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ segsize, 1, /* maxsize, nsegments */ @@ -516,50 +582,46 @@ amr_sglist_map(struct amr_softc *sc) * controller-visible space. * * XXX this assumes we can get enough space for all the s/g maps in one - * contiguous slab. We may need to switch to a more complex arrangement where - * we allocate in smaller chunks and keep a lookup table from slot to bus address. + * contiguous slab. We may need to switch to a more complex arrangement + * where we allocate in smaller chunks and keep a lookup table from slot + * to bus address. * - * XXX HACK ALERT: at least some controllers don't like the s/g memory being - * allocated below 0x2000. We leak some memory if we get some - * below this mark and allocate again. We should be able to - * avoid this with the tag setup, but that does't seem to work. + * XXX HACK ALERT: at least some controllers don't like the s/g memory + * being allocated below 0x2000. We leak some memory if + * we get some below this mark and allocate again. We + * should be able to avoid this with the tag setup, but + * that does't seem to work. */ retry: - error = bus_dmamem_alloc(sc->amr_sg_dmat, (void *)&sc->amr_sgtable, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap); + error = bus_dmamem_alloc(sc->amr_sg_dmat, (void **)&p, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap); if (error) { device_printf(sc->amr_dev, "can't allocate s/g table\n"); return(ENOMEM); } - bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, sc->amr_sgtable, segsize, amr_sglist_map_helper, sc, 0); + bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_helper, &sc->amr_sgbusaddr, 0); if (sc->amr_sgbusaddr < 0x2000) { debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr); goto retry; } + + if (AMR_IS_SG64(sc)) + sc->amr_sg64table = (struct amr_sg64entry *)p; + sc->amr_sgtable = (struct amr_sgentry *)p; + return(0); } /******************************************************************************** * Allocate and set up mailbox areas for the controller (sc) * - * The basic mailbox structure should be 16-byte aligned. This means that the - * mailbox64 structure has 4 bytes hanging off the bottom. + * The basic mailbox structure should be 16-byte aligned. */ -static void -amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct amr_softc *sc = (struct amr_softc *)arg; - - debug_called(1); - - /* save phsyical base of the basic mailbox structure */ - sc->amr_mailboxphys = segs->ds_addr + 16; -} - static int amr_setup_mbox(struct amr_softc *sc) { int error; - u_int8_t *p; + void *p; + uint32_t baddr; debug_called(1); @@ -568,11 +630,12 @@ amr_setup_mbox(struct amr_softc *sc) * mailbox. */ error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ - 16, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ + 16, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - sizeof(struct amr_mailbox) + 16, 1, /* maxsize, nsegments */ + sizeof(struct amr_mailbox64), /* maxsize */ + 1, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ &sc->amr_mailbox_dmat); @@ -585,20 +648,60 @@ amr_setup_mbox(struct amr_softc *sc) * Allocate the mailbox structure and permanently map it into * controller-visible space. */ - error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void *)&p, BUS_DMA_NOWAIT, + error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void **)&p, BUS_DMA_NOWAIT, &sc->amr_mailbox_dmamap); if (error) { device_printf(sc->amr_dev, "can't allocate mailbox memory\n"); return(ENOMEM); } - bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p, - sizeof(struct amr_mailbox64), amr_setup_mbox_helper, sc, 0); + bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p, + sizeof(struct amr_mailbox64), amr_sglist_helper, &baddr, 0); /* * Conventional mailbox is inside the mailbox64 region. */ + /* save physical base of the basic mailbox structure */ + sc->amr_mailboxphys = baddr + offsetof(struct amr_mailbox64, mb); bzero(p, sizeof(struct amr_mailbox64)); - sc->amr_mailbox64 = (struct amr_mailbox64 *)(p + 12); - sc->amr_mailbox = (struct amr_mailbox *)(p + 16); + sc->amr_mailbox64 = (struct amr_mailbox64 *)p; + sc->amr_mailbox = &sc->amr_mailbox64->mb; return(0); } + +static int +amr_ccb_map(struct amr_softc *sc) +{ + int ccbsize, error; + + /* + * Passthrough and Extended passthrough structures will share the same + * memory. + */ + ccbsize = sizeof(union amr_ccb) * AMR_MAXCMD; + error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ + 128, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + ccbsize, /* maxsize */ + 1, /* nsegments */ + ccbsize, /* maxsegsize */ + 0, /* flags */ + &sc->amr_ccb_dmat); + if (error != 0) { + device_printf(sc->amr_dev, "can't allocate ccb tag\n"); + return (ENOMEM); + } + + error = bus_dmamem_alloc(sc->amr_ccb_dmat, (void **)&sc->amr_ccb, + BUS_DMA_NOWAIT, &sc->amr_ccb_dmamap); + if (error) { + device_printf(sc->amr_dev, "can't allocate ccb memory\n"); + return (ENOMEM); + } + bus_dmamap_load(sc->amr_ccb_dmat, sc->amr_ccb_dmamap, sc->amr_ccb, + ccbsize, amr_sglist_helper, &sc->amr_ccb_busaddr, 0); + bzero(sc->amr_ccb, ccbsize); + + return (0); +} diff --git a/sys/dev/raid/amr/amr_tables.h b/sys/dev/raid/amr/amr_tables.h index 1eef464b15..914438ee9d 100644 --- a/sys/dev/raid/amr/amr_tables.h +++ b/sys/dev/raid/amr/amr_tables.h @@ -52,8 +52,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amr_tables.h,v 1.1.2.3 2002/11/11 13:19:10 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amr_tables.h,v 1.2 2003/06/17 04:28:22 dillon Exp $ + * + * $FreeBSD: src/sys/dev/amr/amr_tables.h,v 1.3 2002/10/30 22:00:11 emoore Exp $ */ /* diff --git a/sys/dev/raid/amr/amrio.h b/sys/dev/raid/amr/amrio.h index 0c75da72e9..8849fe482c 100644 --- a/sys/dev/raid/amr/amrio.h +++ b/sys/dev/raid/amr/amrio.h @@ -51,8 +51,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amrio.h,v 1.2.2.3 2002/11/11 13:19:10 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amrio.h,v 1.2 2003/06/17 04:28:22 dillon Exp $ + * + * $FreeBSD: src/sys/dev/amr/amrio.h,v 1.7 2005/12/14 03:26:49 scottl Exp $ */ /* @@ -60,11 +60,12 @@ */ #include +#include /* * Fetch the driver's interface version. */ -#define AMR_IO_VERSION_NUMBER 0x01 +#define AMR_IO_VERSION_NUMBER 153 #define AMR_IO_VERSION _IOR('A', 0x200, int) /* @@ -107,3 +108,15 @@ struct amr_user_ioctl { #define AMR_IO_COMMAND _IOWR('A', 0x201, struct amr_user_ioctl) +#if defined(__amd64__) || defined(__ia64__) + +struct amr_user_ioctl32 { + unsigned char au_cmd[32]; /* command text from userspace */ + u_int32_t au_buffer; /* 32-bit pointer to uspace buf */ + u_int32_t au_length; /* length of the uspace buffer */ + int32_t au_direction; /* data transfer direction */ + int32_t au_status; /* command status returned by adapter */ +}; + +# define AMR_IO_COMMAND32 _IOWR('A', 0x201, struct amr_user_ioctl32) +#endif diff --git a/sys/dev/raid/amr/amrreg.h b/sys/dev/raid/amr/amrreg.h index 7a8ae871ed..051f65ff02 100644 --- a/sys/dev/raid/amr/amrreg.h +++ b/sys/dev/raid/amr/amrreg.h @@ -52,8 +52,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amrreg.h,v 1.1.2.4 2002/11/11 13:19:10 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amrreg.h,v 1.2 2003/06/17 04:28:22 dillon Exp $ + * + * $FreeBSD: src/sys/dev/amr/amrreg.h,v 1.12 2008/02/06 14:26:31 scottl Exp $ */ /******************************************************************************** @@ -82,7 +82,7 @@ #define AMR_LIMITCMD 120 /* maximum count of outstanding commands */ #define AMR_MAXLD 40 -#define AMR_MAX_CHANNELS 4 +#define AMR_MAX_CHANNELS 8 #define AMR_MAX_TARGETS 15 #define AMR_MAX_LUNS 7 #define AMR_MAX_SCSI_CMDS (15 * AMR_MAX_CHANNELS) /* one for every target? */ @@ -119,12 +119,34 @@ #define AMR_CMD_GET_MACHINEID 0x36 #define AMR_CMD_GET_INITIATOR 0x7d /* returns one byte */ #define AMR_CMD_CONFIG 0xa1 +#define AMR_CMD_LREAD64 0xa7 +#define AMR_CMD_LWRITE64 0xa8 +#define AMR_CMD_PASS_64 0xc3 +#define AMR_CMD_EXTPASS 0xe3 + +#define AMR_CONFIG_READ_NVRAM_CONFIG 0x04 +#define AMR_CONFIG_WRITE_NVRAM_CONFIG 0x0d #define AMR_CONFIG_PRODUCT_INFO 0x0e #define AMR_CONFIG_ENQ3 0x0f #define AMR_CONFIG_ENQ3_SOLICITED_NOTIFY 0x01 #define AMR_CONFIG_ENQ3_SOLICITED_FULL 0x02 #define AMR_CONFIG_ENQ3_UNSOLICITED 0x03 -#define AMR_CMD_EXTPASS 0xe3 + +/* + * Command for random deletion of logical drives + */ +#define FC_DEL_LOGDRV 0xA4 +#define OP_SUP_DEL_LOGDRV 0x2A +#define OP_GET_LDID_MAP 0x18 +#define OP_DEL_LOGDRV 0x1C + +/* + * Command for random deletion of logical drives + */ +#define FC_DEL_LOGDRV 0xA4 +#define OP_SUP_DEL_LOGDRV 0x2A +#define OP_GET_LDID_MAP 0x18 +#define OP_DEL_LOGDRV 0x1C /* * Command results @@ -377,8 +399,9 @@ struct amr_enquiry3 u_int16_t ae_opstatus[AMR_40LD_MAXDRIVES / 8]; /* operation status per drive */ u_int32_t ae_drivesize[AMR_40LD_MAXDRIVES]; /* logical drive size */ u_int8_t ae_driveprop[AMR_40LD_MAXDRIVES]; /* logical drive properties */ - u_int8_t ae_drivestate[AMR_40LD_MAXDRIVES]; /* physical drive state */ - u_int16_t ae_driveformat[AMR_40LD_MAXPHYSDRIVES]; + u_int8_t ae_drivestate[AMR_40LD_MAXDRIVES]; /* logical drive state */ + u_int8_t ae_pdrivestate[AMR_40LD_MAXPHYSDRIVES]; /* physical drive state */ + u_int16_t ae_pdriveformat[AMR_40LD_MAXPHYSDRIVES / 16]; u_int8_t ae_targxfer[80]; /* physical drive transfer rates */ u_int8_t res1[263]; /* pad to 1024 bytes */ @@ -397,13 +420,14 @@ struct amr_mailbox { u_int8_t mb_command; u_int8_t mb_ident; - u_int16_t mb_blkcount; + u_int16_t mb_blkcount; /* u_int8_t opcode */ + /* u_int8_t subopcode */ u_int32_t mb_lba; u_int32_t mb_physaddr; u_int8_t mb_drive; - u_int8_t mb_nsgelem; - u_int8_t res1; - u_int8_t mb_busy; + u_int8_t mb_nsgelem; /* u_int8_t rserv[0] */ + u_int8_t res1; /* u_int8_t rserv[1] */ + u_int8_t mb_busy; /* u_int8_t rserv[2] */ u_int8_t mb_nstatus; u_int8_t mb_status; u_int8_t mb_completed[46]; @@ -414,7 +438,9 @@ struct amr_mailbox struct amr_mailbox64 { - u_int32_t mb64_segment; /* for 64-bit controllers */ + u_int8_t pad[8]; /* Needed for alignment */ + u_int32_t sg64_lo; /* S/G pointer for 64-bit commands */ + u_int32_t sg64_hi; /* S/G pointer for 64-bit commands */ struct amr_mailbox mb; } __packed; @@ -443,6 +469,12 @@ struct amr_sgentry u_int32_t sg_count; } __packed; +struct amr_sg64entry +{ + u_int64_t sg_addr; + u_int32_t sg_count; +} __packed; + struct amr_passthrough { u_int8_t ap_timeout:3; @@ -489,6 +521,26 @@ struct amr_ext_passthrough u_int32_t ap_data_transfer_length; } __packed; +struct amr_linux_ioctl { + u_int32_t inlen; + u_int32_t outlen; + union { + u_int8_t fca[16]; + struct { + u_int8_t opcode; + u_int8_t subopcode; + u_int16_t adapno; + u_int32_t buffer; + u_int8_t pad[4]; + u_int32_t length; + } __packed fcs; + } __packed ui; + u_int8_t mbox[18]; + struct amr_passthrough pthru; + u_int32_t data; + u_int8_t pad[4]; +} __packed; + #ifdef _KERNEL /******************************************************************************** ******************************************************************************** diff --git a/sys/dev/raid/amr/amrvar.h b/sys/dev/raid/amr/amrvar.h index 1b35e75ace..534914b665 100644 --- a/sys/dev/raid/amr/amrvar.h +++ b/sys/dev/raid/amr/amrvar.h @@ -52,24 +52,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/amr/amrvar.h,v 1.2.2.5 2002/12/20 15:12:04 emoore Exp $ - * $DragonFly: src/sys/dev/raid/amr/amrvar.h,v 1.11 2008/06/10 17:20:49 dillon Exp $ + * + * $FreeBSD: src/sys/dev/amr/amrvar.h,v 1.37 2010/07/28 16:24:11 mdf Exp $ */ -#include +#include +#include +#include +#include +#include -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 -# include -#endif +#define LSI_DESC_PCI "LSILogic MegaRAID 1.53" #ifdef AMR_DEBUG # define debug(level, fmt, args...) do {if (level <= AMR_DEBUG) kprintf("%s: " fmt "\n", __func__ , ##args);} while(0) # define debug_called(level) do {if (level <= AMR_DEBUG) kprintf("%s: called\n", __func__);} while(0) #else -# define debug(level, fmt, args...) -# define debug_called(level) +# define debug(level, fmt, args...) do {} while (0) +# define debug_called(level) do {} while (0) #endif -#define xdebug(fmt, args...) kprintf("%s: " fmt "\n", __func__ , ##args) +#define xdebug(fmt, args...) printf("%s: " fmt "\n", __func__ , ##args) /* * Per-logical-drive datastructure @@ -100,41 +102,61 @@ struct amr_logdrive #define AMR_CMD_CLUSTERSIZE (16 * 1024) +typedef STAILQ_HEAD(, amr_command) ac_qhead_t; +typedef STAILQ_ENTRY(amr_command) ac_link_t; + +union amr_ccb { + struct amr_passthrough ccb_pthru; + struct amr_ext_passthrough ccb_epthru; + uint8_t bytes[128]; +}; + /* * Per-command control structure. */ struct amr_command { - TAILQ_ENTRY(amr_command) ac_link; + ac_link_t ac_link; struct amr_softc *ac_sc; u_int8_t ac_slot; int ac_status; /* command completion status */ + union { + struct amr_sgentry *sg32; + struct amr_sg64entry *sg64; + } ac_sg; + u_int32_t ac_sgbusaddr; + u_int32_t ac_sg64_lo; + u_int32_t ac_sg64_hi; struct amr_mailbox ac_mailbox; int ac_flags; #define AMR_CMD_DATAIN (1<<0) #define AMR_CMD_DATAOUT (1<<1) -#define AMR_CMD_CCB_DATAIN (1<<2) -#define AMR_CMD_CCB_DATAOUT (1<<3) +#define AMR_CMD_CCB (1<<2) #define AMR_CMD_PRIORITY (1<<4) #define AMR_CMD_MAPPED (1<<5) #define AMR_CMD_SLEEP (1<<6) #define AMR_CMD_BUSY (1<<7) +#define AMR_CMD_SG64 (1<<8) +#define AC_IS_SG64(ac) ((ac)->ac_flags & AMR_CMD_SG64) + u_int ac_retries; struct bio *ac_bio; + void (* ac_complete)(struct amr_command *ac); + void *ac_private; void *ac_data; size_t ac_length; bus_dmamap_t ac_dmamap; - u_int32_t ac_dataphys; + bus_dmamap_t ac_dma64map; - void *ac_ccb_data; - size_t ac_ccb_length; - bus_dmamap_t ac_ccb_dmamap; - u_int32_t ac_ccb_dataphys; + bus_dma_tag_t ac_tag; + bus_dmamap_t ac_datamap; + int ac_nsegments; + uint32_t ac_mb_physaddr; - void (* ac_complete)(struct amr_command *ac); - void *ac_private; + union amr_ccb *ac_ccb; + uint32_t ac_ccb_busaddr; }; struct amr_command_cluster @@ -158,6 +180,7 @@ struct amr_softc bus_space_tag_t amr_btag; bus_dma_tag_t amr_parent_dmat; /* parent DMA tag */ bus_dma_tag_t amr_buffer_dmat; /* data buffer DMA tag */ + bus_dma_tag_t amr_buffer64_dmat; struct resource *amr_irq; /* interrupt */ void *amr_intr; @@ -170,11 +193,18 @@ struct amr_softc /* scatter/gather lists and their controller-visible mappings */ struct amr_sgentry *amr_sgtable; /* s/g lists */ + struct amr_sg64entry *amr_sg64table; /* 64bit s/g lists */ u_int32_t amr_sgbusaddr; /* s/g table base address in bus space */ bus_dma_tag_t amr_sg_dmat; /* s/g buffer DMA tag */ bus_dmamap_t amr_sg_dmamap; /* map for s/g buffers */ + union amr_ccb *amr_ccb; + uint32_t amr_ccb_busaddr; + bus_dma_tag_t amr_ccb_dmat; + bus_dmamap_t amr_ccb_dmamap; + /* controller limits and features */ + int amr_nextslot; /* Next slot to use for newly allocated commands */ int amr_maxio; /* maximum number of I/O transactions */ int amr_maxdrives; /* max number of logical drives */ int amr_maxchan; /* count of SCSI channels */ @@ -188,22 +218,30 @@ struct amr_softc #define AMR_STATE_SUSPEND (1<<1) #define AMR_STATE_INTEN (1<<2) #define AMR_STATE_SHUTDOWN (1<<3) +#define AMR_STATE_CRASHDUMP (1<<4) +#define AMR_STATE_QUEUE_FRZN (1<<5) +#define AMR_STATE_LD_DELETE (1<<6) +#define AMR_STATE_REMAP_LD (1<<7) /* per-controller queues */ struct bio_queue_head amr_bioq; /* pending I/O with no commands */ - TAILQ_HEAD(,amr_command) amr_ready; /* commands ready to be submitted */ + ac_qhead_t amr_ready; /* commands ready to be submitted */ struct amr_command *amr_busycmd[AMR_MAXCMD]; int amr_busyslots; - TAILQ_HEAD(,amr_command) amr_completed; - TAILQ_HEAD(,amr_command) amr_freecmds; + ac_qhead_t amr_freecmds; TAILQ_HEAD(,amr_command_cluster) amr_cmd_clusters; /* CAM attachments for passthrough */ struct cam_sim *amr_cam_sim[AMR_MAX_CHANNELS]; TAILQ_HEAD(, ccb_hdr) amr_cam_ccbq; + struct cam_devq *amr_cam_devq; /* control device */ - cdev_t amr_dev_t; + struct cdev *amr_dev_t; + struct lock amr_list_lock; + + struct sysctl_ctx_list amr_sysctl_ctx; + struct sysctl_oid *amr_sysctl_tree; /* controller type-specific support */ int amr_type; @@ -211,17 +249,23 @@ struct amr_softc #define AMR_IS_QUARTZ(sc) ((sc)->amr_type & AMR_TYPE_QUARTZ) #define AMR_TYPE_40LD (1<<1) #define AMR_IS_40LD(sc) ((sc)->amr_type & AMR_TYPE_40LD) - int (* amr_submit_command)(struct amr_softc *sc); +#define AMR_TYPE_SG64 (1<<2) +#define AMR_IS_SG64(sc) ((sc)->amr_type & AMR_TYPE_SG64) + int (* amr_submit_command)(struct amr_command *ac); int (* amr_get_work)(struct amr_softc *sc, struct amr_mailbox *mbsave); int (*amr_poll_command)(struct amr_command *ac); + int (*amr_poll_command1)(struct amr_softc *sc, struct amr_command *ac); int support_ext_cdb; /* greater than 10 byte cdb support */ /* misc glue */ + device_t amr_pass; + int (*amr_cam_command)(struct amr_softc *sc, struct amr_command **acp); struct intr_config_hook amr_ich; /* wait-for-interrupts probe hook */ struct callout amr_timeout; /* periodic status check */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 - struct task amr_task_complete; /* deferred-completion task */ -#endif + int amr_allow_vol_config; + int amr_linux_no_adapters; + int amr_ld_del_supported; + struct lock amr_hw_lock; }; /* @@ -239,13 +283,6 @@ extern void amr_startio(struct amr_softc *sc); extern struct amr_command *amr_alloccmd(struct amr_softc *sc); extern void amr_releasecmd(struct amr_command *ac); -/* - * CAM interface - */ -extern int amr_cam_attach(struct amr_softc *sc); -extern void amr_cam_detach(struct amr_softc *sc); -extern int amr_cam_command(struct amr_softc *sc, struct amr_command **acp); - /* * MegaRAID logical disk driver */ @@ -258,16 +295,14 @@ struct amrd_softc struct disk amrd_disk; struct devstat amrd_stats; int amrd_unit; - int amrd_flags; -#define AMRD_OPEN (1<<0) /* drive is open (can't detach) */ }; /* * Interface between driver core and disk driver (should be using a bus?) */ extern int amr_submit_bio(struct amr_softc *sc, struct bio *bio); -extern void amrd_intr(struct bio *bio); -extern int amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int blks); +extern int amr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks); +extern void amrd_intr(void *data); /******************************************************************************** * Enqueue/dequeue functions @@ -275,9 +310,8 @@ extern int amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void * static __inline void amr_enqueue_bio(struct amr_softc *sc, struct bio *bio) { - crit_enter(); - bioqdisksort(&sc->amr_bioq, bio); - crit_exit(); + + bioq_insert_tail(&sc->amr_bioq, bio); } static __inline struct bio * @@ -285,27 +319,30 @@ amr_dequeue_bio(struct amr_softc *sc) { struct bio *bio; - crit_enter(); if ((bio = bioq_first(&sc->amr_bioq)) != NULL) bioq_remove(&sc->amr_bioq, bio); - crit_exit(); return(bio); } +static __inline void +amr_init_qhead(ac_qhead_t *head) +{ + + STAILQ_INIT(head); +} + static __inline void amr_enqueue_ready(struct amr_command *ac) { - crit_enter(); - TAILQ_INSERT_TAIL(&ac->ac_sc->amr_ready, ac, ac_link); - crit_exit(); + + STAILQ_INSERT_TAIL(&ac->ac_sc->amr_ready, ac, ac_link); } static __inline void amr_requeue_ready(struct amr_command *ac) { - crit_enter(); - TAILQ_INSERT_HEAD(&ac->ac_sc->amr_ready, ac, ac_link); - crit_exit(); + + STAILQ_INSERT_HEAD(&ac->ac_sc->amr_ready, ac, ac_link); } static __inline struct amr_command * @@ -313,39 +350,33 @@ amr_dequeue_ready(struct amr_softc *sc) { struct amr_command *ac; - crit_enter(); - if ((ac = TAILQ_FIRST(&sc->amr_ready)) != NULL) - TAILQ_REMOVE(&sc->amr_ready, ac, ac_link); - crit_exit(); + if ((ac = STAILQ_FIRST(&sc->amr_ready)) != NULL) + STAILQ_REMOVE_HEAD(&sc->amr_ready, ac_link); return(ac); } static __inline void -amr_enqueue_completed(struct amr_command *ac) +amr_enqueue_completed(struct amr_command *ac, ac_qhead_t *head) { - crit_enter(); - TAILQ_INSERT_TAIL(&ac->ac_sc->amr_completed, ac, ac_link); - crit_exit(); + + STAILQ_INSERT_TAIL(head, ac, ac_link); } static __inline struct amr_command * -amr_dequeue_completed(struct amr_softc *sc) +amr_dequeue_completed(struct amr_softc *sc, ac_qhead_t *head) { struct amr_command *ac; - crit_enter(); - if ((ac = TAILQ_FIRST(&sc->amr_completed)) != NULL) - TAILQ_REMOVE(&sc->amr_completed, ac, ac_link); - crit_exit(); + if ((ac = STAILQ_FIRST(head)) != NULL) + STAILQ_REMOVE_HEAD(head, ac_link); return(ac); } static __inline void amr_enqueue_free(struct amr_command *ac) { - crit_enter(); - TAILQ_INSERT_TAIL(&ac->ac_sc->amr_freecmds, ac, ac_link); - crit_exit(); + + STAILQ_INSERT_HEAD(&ac->ac_sc->amr_freecmds, ac, ac_link); } static __inline struct amr_command * @@ -353,9 +384,7 @@ amr_dequeue_free(struct amr_softc *sc) { struct amr_command *ac; - crit_enter(); - if ((ac = TAILQ_FIRST(&sc->amr_freecmds)) != NULL) - TAILQ_REMOVE(&sc->amr_freecmds, ac, ac_link); - crit_exit(); + if ((ac = STAILQ_FIRST(&sc->amr_freecmds)) != NULL) + STAILQ_REMOVE_HEAD(&sc->amr_freecmds, ac_link); return(ac); }