amr.c revision 138422
151974Smsmith/*-
265245Smsmith * Copyright (c) 1999,2000 Michael Smith
365245Smsmith * Copyright (c) 2000 BSDi
451974Smsmith * All rights reserved.
551974Smsmith *
651974Smsmith * Redistribution and use in source and binary forms, with or without
751974Smsmith * modification, are permitted provided that the following conditions
851974Smsmith * are met:
951974Smsmith * 1. Redistributions of source code must retain the above copyright
1051974Smsmith *    notice, this list of conditions and the following disclaimer.
1151974Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1251974Smsmith *    notice, this list of conditions and the following disclaimer in the
1351974Smsmith *    documentation and/or other materials provided with the distribution.
1451974Smsmith *
1551974Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1651974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1751974Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1851974Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1951974Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2051974Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2151974Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2251974Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2351974Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2451974Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2551974Smsmith * SUCH DAMAGE.
26119418Sobrien */
27119418Sobrien/*
28106225Semoore * Copyright (c) 2002 Eric Moore
29106225Semoore * Copyright (c) 2002 LSI Logic Corporation
30106225Semoore * All rights reserved.
31106225Semoore *
32106225Semoore * Redistribution and use in source and binary forms, with or without
33106225Semoore * modification, are permitted provided that the following conditions
34106225Semoore * are met:
35106225Semoore * 1. Redistributions of source code must retain the above copyright
36106225Semoore *    notice, this list of conditions and the following disclaimer.
37106225Semoore * 2. Redistributions in binary form must reproduce the above copyright
38106225Semoore *    notice, this list of conditions and the following disclaimer in the
39106225Semoore *    documentation and/or other materials provided with the distribution.
40105419Semoore * 3. The party using or redistributing the source code and binary forms
41106225Semoore *    agrees to the disclaimer below and the terms and conditions set forth
42105419Semoore *    herein.
43105419Semoore *
44106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47106225Semoore * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54106225Semoore * SUCH DAMAGE.
5551974Smsmith */
5651974Smsmith
57119418Sobrien#include <sys/cdefs.h>
58119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/amr/amr.c 138422 2004-12-05 23:48:17Z scottl $");
59119418Sobrien
6051974Smsmith/*
6165245Smsmith * Driver for the AMI MegaRaid family of controllers.
6251974Smsmith */
6351974Smsmith
6451974Smsmith#include <sys/param.h>
6551974Smsmith#include <sys/systm.h>
6651974Smsmith#include <sys/malloc.h>
6751974Smsmith#include <sys/kernel.h>
6851974Smsmith
6965245Smsmith#include <dev/amr/amr_compat.h>
7051974Smsmith#include <sys/bus.h>
7151974Smsmith#include <sys/conf.h>
7265245Smsmith#include <sys/stat.h>
7351974Smsmith
7465245Smsmith#include <machine/bus_memio.h>
7565245Smsmith#include <machine/bus_pio.h>
7665245Smsmith#include <machine/bus.h>
7751974Smsmith#include <machine/resource.h>
7851974Smsmith#include <sys/rman.h>
7951974Smsmith
80119277Simp#include <dev/pci/pcireg.h>
81119277Simp#include <dev/pci/pcivar.h>
8265245Smsmith
8351974Smsmith#include <dev/amr/amrio.h>
8451974Smsmith#include <dev/amr/amrreg.h>
8551974Smsmith#include <dev/amr/amrvar.h>
8665245Smsmith#define AMR_DEFINE_TABLES
8765245Smsmith#include <dev/amr/amr_tables.h>
8851974Smsmith
8965245Smsmithstatic d_open_t         amr_open;
9065245Smsmithstatic d_close_t        amr_close;
9165245Smsmithstatic d_ioctl_t        amr_ioctl;
9265245Smsmith
9351974Smsmithstatic struct cdevsw amr_cdevsw = {
94126080Sphk	.d_version =	D_VERSION,
95126080Sphk	.d_flags =	D_NEEDGIANT,
96111815Sphk	.d_open =	amr_open,
97111815Sphk	.d_close =	amr_close,
98111815Sphk	.d_ioctl =	amr_ioctl,
99111815Sphk	.d_name =	"amr",
10051974Smsmith};
10151974Smsmith
10265245Smsmith/*
10365245Smsmith * Initialisation, bus interface.
10465245Smsmith */
10565245Smsmithstatic void	amr_startup(void *arg);
10651974Smsmith
10751974Smsmith/*
10851974Smsmith * Command wrappers
10951974Smsmith */
11065245Smsmithstatic int	amr_query_controller(struct amr_softc *sc);
11165245Smsmithstatic void	*amr_enquiry(struct amr_softc *sc, size_t bufsize,
11265245Smsmith			     u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual);
11365245Smsmithstatic void	amr_completeio(struct amr_command *ac);
114106225Semoorestatic int	amr_support_ext_cdb(struct amr_softc *sc);
11551974Smsmith
11651974Smsmith/*
11765245Smsmith * Command buffer allocation.
11851974Smsmith */
11965245Smsmithstatic void	amr_alloccmd_cluster(struct amr_softc *sc);
12065245Smsmithstatic void	amr_freecmd_cluster(struct amr_command_cluster *acc);
12151974Smsmith
12251974Smsmith/*
12365245Smsmith * Command processing.
12451974Smsmith */
12565245Smsmithstatic int	amr_bio_command(struct amr_softc *sc, struct amr_command **acp);
126138422Sscottlstatic int	amr_wait_command(struct amr_command *ac) __unused;
12765245Smsmithstatic int	amr_getslot(struct amr_command *ac);
128138422Sscottlstatic int	amr_mapcmd(struct amr_command *ac);
12965245Smsmithstatic void	amr_unmapcmd(struct amr_command *ac);
13065245Smsmithstatic int	amr_start(struct amr_command *ac);
131138422Sscottlstatic int	amr_start1(struct amr_softc *sc, struct amr_command *ac);
13265245Smsmithstatic void	amr_complete(void *context, int pending);
133138422Sscottlstatic void	amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
134138422Sscottlstatic void	amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
13551974Smsmith
13651974Smsmith/*
13758883Smsmith * Status monitoring
13858883Smsmith */
13965245Smsmithstatic void	amr_periodic(void *data);
14058883Smsmith
14158883Smsmith/*
14251974Smsmith * Interface-specific shims
14351974Smsmith */
14465245Smsmithstatic int	amr_quartz_submit_command(struct amr_softc *sc);
14565245Smsmithstatic int	amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
146107756Semoorestatic int	amr_quartz_poll_command(struct amr_command *ac);
147138422Sscottlstatic int	amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac);
14851974Smsmith
14965245Smsmithstatic int	amr_std_submit_command(struct amr_softc *sc);
15065245Smsmithstatic int	amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
151107756Semoorestatic int	amr_std_poll_command(struct amr_command *ac);
15265245Smsmithstatic void	amr_std_attach_mailbox(struct amr_softc *sc);
15351974Smsmith
15465245Smsmith#ifdef AMR_BOARD_INIT
15565245Smsmithstatic int	amr_quartz_init(struct amr_softc *sc);
15665245Smsmithstatic int	amr_std_init(struct amr_softc *sc);
15765245Smsmith#endif
15865245Smsmith
15951974Smsmith/*
16051974Smsmith * Debugging
16151974Smsmith */
16265245Smsmithstatic void	amr_describe_controller(struct amr_softc *sc);
16365245Smsmith#ifdef AMR_DEBUG
164107756Semoore#if 0
16565245Smsmithstatic void	amr_printcommand(struct amr_command *ac);
16665245Smsmith#endif
167107756Semoore#endif
16851974Smsmith
16951974Smsmith/********************************************************************************
17051974Smsmith ********************************************************************************
17165245Smsmith                                                                      Inline Glue
17251974Smsmith ********************************************************************************
17351974Smsmith ********************************************************************************/
17451974Smsmith
17551974Smsmith/********************************************************************************
17665245Smsmith ********************************************************************************
17765245Smsmith                                                                Public Interfaces
17865245Smsmith ********************************************************************************
17965245Smsmith ********************************************************************************/
18051974Smsmith
18151974Smsmith/********************************************************************************
18251974Smsmith * Initialise the controller and softc.
18351974Smsmith */
18451974Smsmithint
18551974Smsmithamr_attach(struct amr_softc *sc)
18651974Smsmith{
18751974Smsmith
18865245Smsmith    debug_called(1);
18965245Smsmith
19051974Smsmith    /*
19151974Smsmith     * Initialise per-controller queues.
19251974Smsmith     */
19365245Smsmith    TAILQ_INIT(&sc->amr_completed);
19451974Smsmith    TAILQ_INIT(&sc->amr_freecmds);
19565245Smsmith    TAILQ_INIT(&sc->amr_cmd_clusters);
19665245Smsmith    TAILQ_INIT(&sc->amr_ready);
19759249Sphk    bioq_init(&sc->amr_bioq);
19851974Smsmith
19965245Smsmith#if __FreeBSD_version >= 500005
20051974Smsmith    /*
20165245Smsmith     * Initialise command-completion task.
20265245Smsmith     */
20365245Smsmith    TASK_INIT(&sc->amr_task_complete, 0, amr_complete, sc);
20465245Smsmith#endif
20565245Smsmith
20665245Smsmith    debug(2, "queue init done");
20765245Smsmith
20865245Smsmith    /*
20951974Smsmith     * Configure for this controller type.
21051974Smsmith     */
21165245Smsmith    if (AMR_IS_QUARTZ(sc)) {
21251974Smsmith	sc->amr_submit_command = amr_quartz_submit_command;
21351974Smsmith	sc->amr_get_work       = amr_quartz_get_work;
214107756Semoore	sc->amr_poll_command   = amr_quartz_poll_command;
215138422Sscottl	sc->amr_poll_command1  = amr_quartz_poll_command1;
21651974Smsmith    } else {
21751974Smsmith	sc->amr_submit_command = amr_std_submit_command;
21851974Smsmith	sc->amr_get_work       = amr_std_get_work;
219107756Semoore	sc->amr_poll_command   = amr_std_poll_command;
22065245Smsmith	amr_std_attach_mailbox(sc);;
22151974Smsmith    }
22251974Smsmith
22365245Smsmith#ifdef AMR_BOARD_INIT
22465245Smsmith    if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc))))
22565245Smsmith	return(ENXIO);
22665245Smsmith#endif
22751974Smsmith
22851974Smsmith    /*
22965245Smsmith     * Quiz controller for features and limits.
23051974Smsmith     */
23165245Smsmith    if (amr_query_controller(sc))
23265245Smsmith	return(ENXIO);
23351974Smsmith
23465245Smsmith    debug(2, "controller query complete");
23551974Smsmith
23651974Smsmith    /*
23765245Smsmith     * Attach our 'real' SCSI channels to CAM.
23851974Smsmith     */
23965245Smsmith    if (amr_cam_attach(sc))
24051974Smsmith	return(ENXIO);
24165245Smsmith    debug(2, "CAM attach done");
24251974Smsmith
24351974Smsmith    /*
24465245Smsmith     * Create the control device.
24551974Smsmith     */
24665245Smsmith    sc->amr_dev_t = make_dev(&amr_cdevsw, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR,
24765245Smsmith			     S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev));
24865245Smsmith    sc->amr_dev_t->si_drv1 = sc;
24951974Smsmith
25051974Smsmith    /*
25165245Smsmith     * Schedule ourselves to bring the controller up once interrupts are
25265245Smsmith     * available.
25351974Smsmith     */
25465245Smsmith    bzero(&sc->amr_ich, sizeof(struct intr_config_hook));
25565245Smsmith    sc->amr_ich.ich_func = amr_startup;
25665245Smsmith    sc->amr_ich.ich_arg = sc;
25765245Smsmith    if (config_intrhook_establish(&sc->amr_ich) != 0) {
25865245Smsmith	device_printf(sc->amr_dev, "can't establish configuration hook\n");
25965245Smsmith	return(ENOMEM);
26065245Smsmith    }
26151974Smsmith
26258883Smsmith    /*
26365245Smsmith     * Print a little information about the controller.
26458883Smsmith     */
26565245Smsmith    amr_describe_controller(sc);
26658883Smsmith
26765245Smsmith    debug(2, "attach complete");
26851974Smsmith    return(0);
26951974Smsmith}
27051974Smsmith
27151974Smsmith/********************************************************************************
27251974Smsmith * Locate disk resources and attach children to them.
27351974Smsmith */
27465245Smsmithstatic void
27565245Smsmithamr_startup(void *arg)
27651974Smsmith{
27765245Smsmith    struct amr_softc	*sc = (struct amr_softc *)arg;
27851974Smsmith    struct amr_logdrive	*dr;
27951974Smsmith    int			i, error;
28051974Smsmith
28165245Smsmith    debug_called(1);
28251974Smsmith
28365245Smsmith    /* pull ourselves off the intrhook chain */
28465245Smsmith    config_intrhook_disestablish(&sc->amr_ich);
28565245Smsmith
28651974Smsmith    /* get up-to-date drive information */
28751974Smsmith    if (amr_query_controller(sc)) {
28865245Smsmith	device_printf(sc->amr_dev, "can't scan controller for drives\n");
28951974Smsmith	return;
29051974Smsmith    }
29151974Smsmith
29251974Smsmith    /* iterate over available drives */
29351974Smsmith    for (i = 0, dr = &sc->amr_drive[0]; (i < AMR_MAXLD) && (dr->al_size != 0xffffffff); i++, dr++) {
29451974Smsmith	/* are we already attached to this drive? */
29551974Smsmith	if (dr->al_disk == 0) {
29651974Smsmith	    /* generate geometry information */
29751974Smsmith	    if (dr->al_size > 0x200000) {	/* extended translation? */
29851974Smsmith		dr->al_heads = 255;
29951974Smsmith		dr->al_sectors = 63;
30051974Smsmith	    } else {
30151974Smsmith		dr->al_heads = 64;
30251974Smsmith		dr->al_sectors = 32;
30351974Smsmith	    }
30451974Smsmith	    dr->al_cylinders = dr->al_size / (dr->al_heads * dr->al_sectors);
30551974Smsmith
30654073Smdodd	    dr->al_disk = device_add_child(sc->amr_dev, NULL, -1);
30751974Smsmith	    if (dr->al_disk == 0)
30851974Smsmith		device_printf(sc->amr_dev, "device_add_child failed\n");
30954073Smdodd	    device_set_ivars(dr->al_disk, dr);
31051974Smsmith	}
31151974Smsmith    }
31251974Smsmith
31351974Smsmith    if ((error = bus_generic_attach(sc->amr_dev)) != 0)
31451974Smsmith	device_printf(sc->amr_dev, "bus_generic_attach returned %d\n", error);
31551974Smsmith
31651974Smsmith    /* mark controller back up */
31751974Smsmith    sc->amr_state &= ~AMR_STATE_SHUTDOWN;
31851974Smsmith
31951974Smsmith    /* interrupts will be enabled before we do anything more */
32051974Smsmith    sc->amr_state |= AMR_STATE_INTEN;
32151974Smsmith
32251974Smsmith    /*
32365245Smsmith     * Start the timeout routine.
32451974Smsmith     */
32565245Smsmith/*    sc->amr_timeout = timeout(amr_periodic, sc, hz);*/
32651974Smsmith
32765245Smsmith    return;
32851974Smsmith}
32951974Smsmith
33065245Smsmith/*******************************************************************************
33165245Smsmith * Free resources associated with a controller instance
33251974Smsmith */
33365245Smsmithvoid
33465245Smsmithamr_free(struct amr_softc *sc)
33551974Smsmith{
33665245Smsmith    struct amr_command_cluster	*acc;
33751974Smsmith
33865245Smsmith    /* detach from CAM */
339107756Semoore    amr_cam_detach(sc);
34051974Smsmith
34165245Smsmith    /* cancel status timeout */
34265245Smsmith    untimeout(amr_periodic, sc, sc->amr_timeout);
34351974Smsmith
34465245Smsmith    /* throw away any command buffers */
34565245Smsmith    while ((acc = TAILQ_FIRST(&sc->amr_cmd_clusters)) != NULL) {
34665245Smsmith	TAILQ_REMOVE(&sc->amr_cmd_clusters, acc, acc_link);
34765245Smsmith	amr_freecmd_cluster(acc);
34851974Smsmith    }
349107756Semoore
350107756Semoore    /* destroy control device */
351130585Sphk    if( sc->amr_dev_t != (struct cdev *)NULL)
352107756Semoore	    destroy_dev(sc->amr_dev_t);
35351974Smsmith}
35451974Smsmith
35551974Smsmith/*******************************************************************************
35665245Smsmith * Receive a bio structure from a child device and queue it on a particular
35751974Smsmith * disk resource, then poke the disk resource to start as much work as it can.
35851974Smsmith */
35951974Smsmithint
36065245Smsmithamr_submit_bio(struct amr_softc *sc, struct bio *bio)
36151974Smsmith{
36265245Smsmith    debug_called(2);
36352543Smsmith
36465245Smsmith    amr_enqueue_bio(sc, bio);
36551974Smsmith    amr_startio(sc);
36651974Smsmith    return(0);
36751974Smsmith}
36851974Smsmith
36951974Smsmith/********************************************************************************
37051974Smsmith * Accept an open operation on the control device.
37151974Smsmith */
372104094Sphkstatic int
373130585Sphkamr_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
37451974Smsmith{
37551974Smsmith    int			unit = minor(dev);
37689055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
37751974Smsmith
37865245Smsmith    debug_called(1);
37965245Smsmith
38051974Smsmith    sc->amr_state |= AMR_STATE_OPEN;
38151974Smsmith    return(0);
38251974Smsmith}
38351974Smsmith
38451974Smsmith/********************************************************************************
38551974Smsmith * Accept the last close on the control device.
38651974Smsmith */
387104094Sphkstatic int
388130585Sphkamr_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
38951974Smsmith{
39051974Smsmith    int			unit = minor(dev);
39189055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
39251974Smsmith
39365245Smsmith    debug_called(1);
39465245Smsmith
39551974Smsmith    sc->amr_state &= ~AMR_STATE_OPEN;
39651974Smsmith    return (0);
39751974Smsmith}
39851974Smsmith
39951974Smsmith/********************************************************************************
40051974Smsmith * Handle controller-specific control operations.
40151974Smsmith */
402104094Sphkstatic int
403130585Sphkamr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
40451974Smsmith{
40565245Smsmith    struct amr_softc		*sc = (struct amr_softc *)dev->si_drv1;
406133870Sambrisko    union {
407133870Sambrisko	void			*_p;
408133870Sambrisko	struct amr_user_ioctl	*au;
409133870Sambrisko#ifdef AMR_IO_COMMAND32
410133870Sambrisko	struct amr_user_ioctl32	*au32;
411133870Sambrisko#endif
412133870Sambrisko	int			*result;
413133870Sambrisko    } arg;
41465245Smsmith    struct amr_command		*ac;
41565245Smsmith    struct amr_mailbox_ioctl	*mbi;
41665245Smsmith    struct amr_passthrough	*ap;
417133870Sambrisko    void			*dp, *au_buffer;
418133870Sambrisko    unsigned long		au_length;
419133870Sambrisko    unsigned char		*au_cmd;
420133870Sambrisko    int				*au_statusp, au_direction;
42165245Smsmith    int				error;
42265245Smsmith
42365245Smsmith    debug_called(1);
42465245Smsmith
425133870Sambrisko    arg._p = (void *)addr;
426133870Sambrisko
42751974Smsmith    switch(cmd) {
42865245Smsmith
42965245Smsmith    case AMR_IO_VERSION:
43065245Smsmith	debug(1, "AMR_IO_VERSION");
431133870Sambrisko	*arg.result = AMR_IO_VERSION_NUMBER;
432133870Sambrisko	return(0);
433133870Sambrisko
434133870Sambrisko#ifdef AMR_IO_COMMAND32
435133870Sambrisko    /*
436133870Sambrisko     * Accept ioctl-s from 32-bit binaries on non-32-bit
437133870Sambrisko     * platforms, such as AMD. LSI's MEGAMGR utility is
438133870Sambrisko     * the only example known today...	-mi
439133870Sambrisko     */
440133870Sambrisko    case AMR_IO_COMMAND32:
441133870Sambrisko	debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]);
442133870Sambrisko	au_cmd = arg.au32->au_cmd;
443133870Sambrisko	au_buffer = (void *)(u_int64_t)arg.au32->au_buffer;
444133870Sambrisko	au_length = arg.au32->au_length;
445133870Sambrisko	au_direction = arg.au32->au_direction;
446133870Sambrisko	au_statusp = &arg.au32->au_status;
44765245Smsmith	break;
448133870Sambrisko#endif
44965245Smsmith
45065245Smsmith    case AMR_IO_COMMAND:
451133870Sambrisko	debug(1, "AMR_IO_COMMAND  0x%x", arg.au->au_cmd[0]);
452133870Sambrisko	au_cmd = arg.au->au_cmd;
453133870Sambrisko	au_buffer = (void *)arg.au->au_buffer;
454133870Sambrisko	au_length = arg.au->au_length;
455133870Sambrisko	au_direction = arg.au->au_direction;
456133870Sambrisko	au_statusp = &arg.au->au_status;
457133870Sambrisko	break;
45865245Smsmith
459133870Sambrisko    default:
460133870Sambrisko	debug(1, "unknown ioctl 0x%lx", cmd);
461133870Sambrisko	return(ENOIOCTL);
462133870Sambrisko    }
46365245Smsmith
464133870Sambrisko    error = 0;
465133870Sambrisko    dp = NULL;
466133870Sambrisko    ap = NULL;
467133870Sambrisko    ac = NULL;
46865245Smsmith
469133870Sambrisko    /* handle inbound data buffer */
470133870Sambrisko    if (au_length != 0) {
471133870Sambrisko	if ((dp = malloc(au_length, M_DEVBUF, M_WAITOK)) == NULL)
472133870Sambrisko	    return(ENOMEM);
47365245Smsmith
474133870Sambrisko	if ((error = copyin(au_buffer, dp, au_length)) != 0)
475133870Sambrisko	    goto out;
476133870Sambrisko	debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp);
477133870Sambrisko    }
47865245Smsmith
479133870Sambrisko    if ((ac = amr_alloccmd(sc)) == NULL) {
480133870Sambrisko	error = ENOMEM;
481133870Sambrisko	goto out;
482133870Sambrisko    }
48365245Smsmith
484133870Sambrisko    /* handle SCSI passthrough command */
485133870Sambrisko    if (au_cmd[0] == AMR_CMD_PASS) {
486133870Sambrisko	if ((ap = malloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
487133870Sambrisko	    error = ENOMEM;
488133870Sambrisko	    goto out;
489133870Sambrisko	}
49065245Smsmith
491133870Sambrisko	/* copy cdb */
492133870Sambrisko	ap->ap_cdb_length = au_cmd[2];
493133870Sambrisko	bcopy(au_cmd + 3, ap->ap_cdb, ap->ap_cdb_length);
49465245Smsmith
495133870Sambrisko	/* build passthrough */
496133870Sambrisko	ap->ap_timeout		= au_cmd[ap->ap_cdb_length + 3] & 0x07;
497133870Sambrisko	ap->ap_ars		= (au_cmd[ap->ap_cdb_length + 3] & 0x08) ? 1 : 0;
498133870Sambrisko	ap->ap_islogical	= (au_cmd[ap->ap_cdb_length + 3] & 0x80) ? 1 : 0;
499133870Sambrisko	ap->ap_logical_drive_no	= au_cmd[ap->ap_cdb_length + 4];
500133870Sambrisko	ap->ap_channel		= au_cmd[ap->ap_cdb_length + 5];
501133870Sambrisko	ap->ap_scsi_id 		= au_cmd[ap->ap_cdb_length + 6];
502133870Sambrisko	ap->ap_request_sense_length	= 14;
503133870Sambrisko	ap->ap_data_transfer_length	= au_length;
504133870Sambrisko	/* XXX what about the request-sense area? does the caller want it? */
50565245Smsmith
506133870Sambrisko	/* build command */
507133870Sambrisko	ac->ac_data = ap;
508133870Sambrisko	ac->ac_length = sizeof(*ap);
509133870Sambrisko	ac->ac_flags |= AMR_CMD_DATAOUT;
510133870Sambrisko	ac->ac_ccb_data = dp;
511133870Sambrisko	ac->ac_ccb_length = au_length;
512133870Sambrisko	if (au_direction & AMR_IO_READ)
513133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAIN;
514133870Sambrisko	if (au_direction & AMR_IO_WRITE)
515133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
51665245Smsmith
517133870Sambrisko	ac->ac_mailbox.mb_command = AMR_CMD_PASS;
51865245Smsmith
519133870Sambrisko    } else {
520133870Sambrisko	/* direct command to controller */
521133870Sambrisko	mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
522105419Semoore
523133870Sambrisko	/* copy pertinent mailbox items */
524133870Sambrisko	mbi->mb_command = au_cmd[0];
525133870Sambrisko	mbi->mb_channel = au_cmd[1];
526133870Sambrisko	mbi->mb_param = au_cmd[2];
527133870Sambrisko	mbi->mb_pad[0] = au_cmd[3];
528133870Sambrisko	mbi->mb_drive = au_cmd[4];
529133870Sambrisko
530133870Sambrisko	/* build the command */
531133870Sambrisko	ac->ac_data = dp;
532133870Sambrisko	ac->ac_length = au_length;
533133870Sambrisko	if (au_direction & AMR_IO_READ)
534133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAIN;
535133870Sambrisko	if (au_direction & AMR_IO_WRITE)
536133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAOUT;
53751974Smsmith    }
53851974Smsmith
539133870Sambrisko    /* run the command */
540133870Sambrisko    if ((error = amr_wait_command(ac)) != 0)
541133870Sambrisko	goto out;
542133870Sambrisko
543133870Sambrisko    /* copy out data and set status */
544133870Sambrisko    if (au_length != 0)
545133870Sambrisko	error = copyout(dp, au_buffer, au_length);
546133870Sambrisko    debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
54765245Smsmith    if (dp != NULL)
548133870Sambrisko	debug(2, "%16d", (int)dp);
549133870Sambrisko    *au_statusp = ac->ac_status;
550133870Sambrisko
551133870Sambriskoout:
552133870Sambrisko    if (dp != NULL)
55365245Smsmith	free(dp, M_DEVBUF);
55465245Smsmith    if (ap != NULL)
55565245Smsmith	free(ap, M_DEVBUF);
55665245Smsmith    if (ac != NULL)
55765245Smsmith	amr_releasecmd(ac);
55865245Smsmith    return(error);
55951974Smsmith}
56051974Smsmith
56151974Smsmith/********************************************************************************
56251974Smsmith ********************************************************************************
56358883Smsmith                                                                Status Monitoring
56458883Smsmith ********************************************************************************
56558883Smsmith ********************************************************************************/
56658883Smsmith
56758883Smsmith/********************************************************************************
56858883Smsmith * Perform a periodic check of the controller status
56958883Smsmith */
57058883Smsmithstatic void
57158883Smsmithamr_periodic(void *data)
57258883Smsmith{
57358883Smsmith    struct amr_softc	*sc = (struct amr_softc *)data;
57458883Smsmith
57565245Smsmith    debug_called(2);
57658883Smsmith
57765245Smsmith    /* XXX perform periodic status checks here */
57858883Smsmith
57965245Smsmith    /* compensate for missed interrupts */
58065245Smsmith    amr_done(sc);
58165245Smsmith
58258883Smsmith    /* reschedule */
58358883Smsmith    sc->amr_timeout = timeout(amr_periodic, sc, hz);
58458883Smsmith}
58558883Smsmith
58658883Smsmith/********************************************************************************
58758883Smsmith ********************************************************************************
58851974Smsmith                                                                 Command Wrappers
58951974Smsmith ********************************************************************************
59051974Smsmith ********************************************************************************/
59151974Smsmith
59251974Smsmith/********************************************************************************
59351974Smsmith * Interrogate the controller for the operational parameters we require.
59451974Smsmith */
59551974Smsmithstatic int
59651974Smsmithamr_query_controller(struct amr_softc *sc)
59751974Smsmith{
59865245Smsmith    struct amr_enquiry3	*aex;
59965245Smsmith    struct amr_prodinfo	*ap;
60065245Smsmith    struct amr_enquiry	*ae;
60165245Smsmith    int			ldrv;
60251974Smsmith
60365245Smsmith    /*
60465245Smsmith     * If we haven't found the real limit yet, let us have a couple of commands in
60565245Smsmith     * order to be able to probe.
60665245Smsmith     */
60765245Smsmith    if (sc->amr_maxio == 0)
60865245Smsmith	sc->amr_maxio = 2;
60951974Smsmith
610106225Semoore    /*
611106225Semoore     * Greater than 10 byte cdb support
612106225Semoore     */
613106225Semoore    sc->support_ext_cdb = amr_support_ext_cdb(sc);
614106225Semoore
615106225Semoore    if(sc->support_ext_cdb) {
616106225Semoore	debug(2,"supports extended CDBs.");
617106225Semoore    }
618106225Semoore
61965245Smsmith    /*
62065245Smsmith     * Try to issue an ENQUIRY3 command
62165245Smsmith     */
62265245Smsmith    if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
62365245Smsmith			   AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
62451974Smsmith
62565245Smsmith	/*
62665245Smsmith	 * Fetch current state of logical drives.
62765245Smsmith	 */
62865245Smsmith	for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
62965245Smsmith	    sc->amr_drive[ldrv].al_size       = aex->ae_drivesize[ldrv];
63065245Smsmith	    sc->amr_drive[ldrv].al_state      = aex->ae_drivestate[ldrv];
63165245Smsmith	    sc->amr_drive[ldrv].al_properties = aex->ae_driveprop[ldrv];
63265245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
63365245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
63451974Smsmith	}
63565245Smsmith	free(aex, M_DEVBUF);
63658883Smsmith
63765245Smsmith	/*
63865245Smsmith	 * Get product info for channel count.
63958883Smsmith	 */
64065245Smsmith	if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
64165245Smsmith	    device_printf(sc->amr_dev, "can't obtain product data from controller\n");
64265245Smsmith	    return(1);
64365245Smsmith	}
64465245Smsmith	sc->amr_maxdrives = 40;
64565245Smsmith	sc->amr_maxchan = ap->ap_nschan;
64665245Smsmith	sc->amr_maxio = ap->ap_maxio;
64765245Smsmith	sc->amr_type |= AMR_TYPE_40LD;
64865245Smsmith	free(ap, M_DEVBUF);
64958883Smsmith
65065245Smsmith    } else {
65165245Smsmith
65265245Smsmith	/* failed, try the 8LD ENQUIRY commands */
65365245Smsmith	if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) {
65465245Smsmith	    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) {
65565245Smsmith		device_printf(sc->amr_dev, "can't obtain configuration data from controller\n");
65665245Smsmith		return(1);
65765245Smsmith	    }
65865245Smsmith	    ae->ae_signature = 0;
65951974Smsmith	}
66065245Smsmith
66158883Smsmith	/*
66265245Smsmith	 * Fetch current state of logical drives.
66358883Smsmith	 */
66465245Smsmith	for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
66565245Smsmith	    sc->amr_drive[ldrv].al_size       = ae->ae_ldrv.al_size[ldrv];
66665245Smsmith	    sc->amr_drive[ldrv].al_state      = ae->ae_ldrv.al_state[ldrv];
66765245Smsmith	    sc->amr_drive[ldrv].al_properties = ae->ae_ldrv.al_properties[ldrv];
66865245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
66965245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
67051974Smsmith	}
67165245Smsmith
67265245Smsmith	sc->amr_maxdrives = 8;
67365245Smsmith	sc->amr_maxchan = ae->ae_adapter.aa_channels;
67465245Smsmith	sc->amr_maxio = ae->ae_adapter.aa_maxio;
67565245Smsmith	free(ae, M_DEVBUF);
67651974Smsmith    }
67765245Smsmith
67865245Smsmith    /*
67965245Smsmith     * Mark remaining drives as unused.
68065245Smsmith     */
68165245Smsmith    for (; ldrv < AMR_MAXLD; ldrv++)
68265245Smsmith	sc->amr_drive[ldrv].al_size = 0xffffffff;
68365245Smsmith
68465245Smsmith    /*
68565245Smsmith     * Cap the maximum number of outstanding I/Os.  AMI's Linux driver doesn't trust
68665245Smsmith     * the controller's reported value, and lockups have been seen when we do.
68765245Smsmith     */
68865245Smsmith    sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD);
68965245Smsmith
69051974Smsmith    return(0);
69151974Smsmith}
69251974Smsmith
69351974Smsmith/********************************************************************************
69451974Smsmith * Run a generic enquiry-style command.
69551974Smsmith */
69651974Smsmithstatic void *
69751974Smsmithamr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
69851974Smsmith{
69951974Smsmith    struct amr_command	*ac;
70051974Smsmith    void		*result;
70151974Smsmith    u_int8_t		*mbox;
70251974Smsmith    int			error;
70351974Smsmith
70465245Smsmith    debug_called(1);
70551974Smsmith
70651974Smsmith    error = 1;
70751974Smsmith    result = NULL;
70851974Smsmith
70951974Smsmith    /* get ourselves a command buffer */
71051974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
71151974Smsmith	goto out;
71251974Smsmith    /* allocate the response structure */
713138422Sscottl    if ((result = malloc(bufsize, M_DEVBUF, M_ZERO|M_NOWAIT)) == NULL)
71451974Smsmith	goto out;
71565245Smsmith    /* set command flags */
716138422Sscottl
717135236Sscottl    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN;
71851974Smsmith
71965245Smsmith    /* point the command at our data */
72051974Smsmith    ac->ac_data = result;
72151974Smsmith    ac->ac_length = bufsize;
72251974Smsmith
72351974Smsmith    /* build the command proper */
72451974Smsmith    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
72551974Smsmith    mbox[0] = cmd;
72651974Smsmith    mbox[2] = cmdsub;
72751974Smsmith    mbox[3] = cmdqual;
72851974Smsmith
72958883Smsmith    /* can't assume that interrupts are going to work here, so play it safe */
730107756Semoore    if (sc->amr_poll_command(ac))
73151974Smsmith	goto out;
73251974Smsmith    error = ac->ac_status;
73351974Smsmith
73451974Smsmith out:
73551974Smsmith    if (ac != NULL)
73651974Smsmith	amr_releasecmd(ac);
73751974Smsmith    if ((error != 0) && (result != NULL)) {
73851974Smsmith	free(result, M_DEVBUF);
73951974Smsmith	result = NULL;
74051974Smsmith    }
74151974Smsmith    return(result);
74251974Smsmith}
74351974Smsmith
74451974Smsmith/********************************************************************************
74551974Smsmith * Flush the controller's internal cache, return status.
74651974Smsmith */
74765245Smsmithint
74851974Smsmithamr_flush(struct amr_softc *sc)
74951974Smsmith{
75051974Smsmith    struct amr_command	*ac;
75151974Smsmith    int			error;
75251974Smsmith
75351974Smsmith    /* get ourselves a command buffer */
75451974Smsmith    error = 1;
75551974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
75651974Smsmith	goto out;
75765245Smsmith    /* set command flags */
75851974Smsmith    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
75951974Smsmith
76051974Smsmith    /* build the command proper */
76151974Smsmith    ac->ac_mailbox.mb_command = AMR_CMD_FLUSH;
76251974Smsmith
76358883Smsmith    /* we have to poll, as the system may be going down or otherwise damaged */
764107756Semoore    if (sc->amr_poll_command(ac))
76551974Smsmith	goto out;
76651974Smsmith    error = ac->ac_status;
76751974Smsmith
76851974Smsmith out:
76951974Smsmith    if (ac != NULL)
77051974Smsmith	amr_releasecmd(ac);
77151974Smsmith    return(error);
77251974Smsmith}
77351974Smsmith
77451974Smsmith/********************************************************************************
775106225Semoore * Detect extented cdb >> greater than 10 byte cdb support
776106225Semoore * returns '1' means this support exist
777106225Semoore * returns '0' means this support doesn't exist
778106225Semoore */
779106225Semoorestatic int
780106225Semooreamr_support_ext_cdb(struct amr_softc *sc)
781106225Semoore{
782106225Semoore    struct amr_command	*ac;
783106225Semoore    u_int8_t		*mbox;
784106225Semoore    int			error;
785106225Semoore
786106225Semoore    /* get ourselves a command buffer */
787106225Semoore    error = 0;
788106225Semoore    if ((ac = amr_alloccmd(sc)) == NULL)
789106225Semoore	goto out;
790106225Semoore    /* set command flags */
791106225Semoore    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
792106225Semoore
793106225Semoore    /* build the command proper */
794106225Semoore    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
795106225Semoore    mbox[0] = 0xA4;
796106225Semoore    mbox[2] = 0x16;
797106225Semoore
798106225Semoore
799106225Semoore    /* we have to poll, as the system may be going down or otherwise damaged */
800107756Semoore    if (sc->amr_poll_command(ac))
801106225Semoore	goto out;
802106225Semoore    if( ac->ac_status == AMR_STATUS_SUCCESS ) {
803106225Semoore	    error = 1;
804106225Semoore    }
805106225Semoore
806106225Semooreout:
807106225Semoore    if (ac != NULL)
808106225Semoore	amr_releasecmd(ac);
809106225Semoore    return(error);
810106225Semoore}
811106225Semoore
812106225Semoore/********************************************************************************
81365245Smsmith * Try to find I/O work for the controller from one or more of the work queues.
81451974Smsmith *
81565245Smsmith * We make the assumption that if the controller is not ready to take a command
81665245Smsmith * at some given time, it will generate an interrupt at some later time when
81765245Smsmith * it is.
81851974Smsmith */
81965245Smsmithvoid
82051974Smsmithamr_startio(struct amr_softc *sc)
82151974Smsmith{
82251974Smsmith    struct amr_command	*ac;
82351974Smsmith
82451974Smsmith    /* spin until something prevents us from doing any work */
82551974Smsmith    for (;;) {
82651974Smsmith
827138422Sscottl	/* Don't bother to queue commands no bounce buffers are available. */
828138422Sscottl	if (sc->amr_state & AMR_STATE_QUEUE_FRZN)
829138422Sscottl	    break;
830138422Sscottl
83165245Smsmith	/* try to get a ready command */
83265245Smsmith	ac = amr_dequeue_ready(sc);
83351974Smsmith
83465245Smsmith	/* if that failed, build a command from a bio */
83565245Smsmith	if (ac == NULL)
83665245Smsmith	    (void)amr_bio_command(sc, &ac);
83751974Smsmith
83865245Smsmith	/* if that failed, build a command from a ccb */
83965245Smsmith	if (ac == NULL)
84065245Smsmith	    (void)amr_cam_command(sc, &ac);
841105419Semoore
84265245Smsmith	/* if we don't have anything to do, give up */
84365245Smsmith	if (ac == NULL)
84465245Smsmith	    break;
84551974Smsmith
84665245Smsmith	/* try to give the command to the controller; if this fails save it for later and give up */
84765245Smsmith	if (amr_start(ac)) {
84865245Smsmith	    debug(2, "controller busy, command deferred");
84965245Smsmith	    amr_requeue_ready(ac);	/* XXX schedule retry very soon? */
85065245Smsmith	    break;
85151974Smsmith	}
85251974Smsmith    }
85351974Smsmith}
85451974Smsmith
85551974Smsmith/********************************************************************************
85651974Smsmith * Handle completion of an I/O command.
85751974Smsmith */
85851974Smsmithstatic void
85951974Smsmithamr_completeio(struct amr_command *ac)
86051974Smsmith{
86151974Smsmith    struct amr_softc	*sc = ac->ac_sc;
86251974Smsmith
86351974Smsmith    if (ac->ac_status != AMR_STATUS_SUCCESS) {	/* could be more verbose here? */
86465245Smsmith	ac->ac_bio->bio_error = EIO;
86565245Smsmith	ac->ac_bio->bio_flags |= BIO_ERROR;
86651974Smsmith
86765245Smsmith	device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status);
86865245Smsmith/*	amr_printcommand(ac);*/
86951974Smsmith    }
87065245Smsmith    amrd_intr(ac->ac_bio);
87165245Smsmith    amr_releasecmd(ac);
87251974Smsmith}
87351974Smsmith
87451974Smsmith/********************************************************************************
87551974Smsmith ********************************************************************************
87651974Smsmith                                                               Command Processing
87751974Smsmith ********************************************************************************
87851974Smsmith ********************************************************************************/
87951974Smsmith
88051974Smsmith/********************************************************************************
88165245Smsmith * Convert a bio off the top of the bio queue into a command.
88265245Smsmith */
88365245Smsmithstatic int
88465245Smsmithamr_bio_command(struct amr_softc *sc, struct amr_command **acp)
88565245Smsmith{
88665245Smsmith    struct amr_command	*ac;
88765245Smsmith    struct amrd_softc	*amrd;
88865245Smsmith    struct bio		*bio;
88965245Smsmith    int			error;
89065245Smsmith    int			blkcount;
89165245Smsmith    int			driveno;
89265245Smsmith    int			cmd;
89365245Smsmith
89465245Smsmith    ac = NULL;
89565245Smsmith    error = 0;
89665245Smsmith
89765245Smsmith    /* get a bio to work on */
89865245Smsmith    if ((bio = amr_dequeue_bio(sc)) == NULL)
89965245Smsmith	goto out;
90065245Smsmith
90165245Smsmith    /* get a command */
90265245Smsmith    if ((ac = amr_alloccmd(sc)) == NULL) {
90365245Smsmith	error = ENOMEM;
90465245Smsmith	goto out;
90565245Smsmith    }
90665245Smsmith
90765245Smsmith    /* connect the bio to the command */
90865245Smsmith    ac->ac_complete = amr_completeio;
90965245Smsmith    ac->ac_bio = bio;
91065245Smsmith    ac->ac_data = bio->bio_data;
91165245Smsmith    ac->ac_length = bio->bio_bcount;
91265245Smsmith    if (BIO_IS_READ(bio)) {
91365245Smsmith	ac->ac_flags |= AMR_CMD_DATAIN;
91465245Smsmith	cmd = AMR_CMD_LREAD;
91565245Smsmith    } else {
91665245Smsmith	ac->ac_flags |= AMR_CMD_DATAOUT;
91765245Smsmith	cmd = AMR_CMD_LWRITE;
91865245Smsmith    }
919111441Sphk    amrd = (struct amrd_softc *)bio->bio_disk->d_drv1;
92065245Smsmith    driveno = amrd->amrd_drive - sc->amr_drive;
92165245Smsmith    blkcount = (bio->bio_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE;
92265245Smsmith
92365245Smsmith    ac->ac_mailbox.mb_command = cmd;
92465245Smsmith    ac->ac_mailbox.mb_blkcount = blkcount;
92565245Smsmith    ac->ac_mailbox.mb_lba = bio->bio_pblkno;
92665245Smsmith    ac->ac_mailbox.mb_drive = driveno;
92765245Smsmith    /* we fill in the s/g related data when the command is mapped */
92865245Smsmith
92965245Smsmith    if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size)
93092610Sbde	device_printf(sc->amr_dev, "I/O beyond end of unit (%lld,%d > %lu)\n",
93192610Sbde		      (long long)bio->bio_pblkno, blkcount,
93292610Sbde		      (u_long)sc->amr_drive[driveno].al_size);
93365245Smsmith
93465245Smsmithout:
93565245Smsmith    if (error != 0) {
93665245Smsmith	if (ac != NULL)
93765245Smsmith	    amr_releasecmd(ac);
93865245Smsmith	if (bio != NULL)			/* this breaks ordering... */
93965245Smsmith	    amr_enqueue_bio(sc, bio);
94065245Smsmith    }
94165245Smsmith    *acp = ac;
94265245Smsmith    return(error);
94365245Smsmith}
94465245Smsmith
94565245Smsmith/********************************************************************************
94651974Smsmith * Take a command, submit it to the controller and sleep until it completes
94751974Smsmith * or fails.  Interrupts must be enabled, returns nonzero on error.
94851974Smsmith */
94951974Smsmithstatic int
95051974Smsmithamr_wait_command(struct amr_command *ac)
95151974Smsmith{
95251974Smsmith    int			error, count;
95351974Smsmith
95465245Smsmith    debug_called(1);
95551974Smsmith
95651974Smsmith    ac->ac_complete = NULL;
95765245Smsmith    ac->ac_flags |= AMR_CMD_SLEEP;
95851974Smsmith    if ((error = amr_start(ac)) != 0)
95951974Smsmith	return(error);
96051974Smsmith
96151974Smsmith    count = 0;
96251974Smsmith    /* XXX better timeout? */
96365245Smsmith    while ((ac->ac_flags & AMR_CMD_BUSY) && (count < 30)) {
96465245Smsmith	tsleep(ac, PRIBIO | PCATCH, "amrwcmd", hz);
96551974Smsmith    }
96651974Smsmith    return(0);
96751974Smsmith}
96851974Smsmith
96951974Smsmith/********************************************************************************
97051974Smsmith * Take a command, submit it to the controller and busy-wait for it to return.
97151974Smsmith * Returns nonzero on error.  Can be safely called with interrupts enabled.
97251974Smsmith */
97351974Smsmithstatic int
974107756Semooreamr_std_poll_command(struct amr_command *ac)
97551974Smsmith{
97651974Smsmith    struct amr_softc	*sc = ac->ac_sc;
97765245Smsmith    int			error, count;
97851974Smsmith
97965245Smsmith    debug_called(2);
98051974Smsmith
98151974Smsmith    ac->ac_complete = NULL;
98251974Smsmith    if ((error = amr_start(ac)) != 0)
98351974Smsmith	return(error);
98451974Smsmith
98551974Smsmith    count = 0;
98651974Smsmith    do {
98751974Smsmith	/*
98851974Smsmith	 * Poll for completion, although the interrupt handler may beat us to it.
98951974Smsmith	 * Note that the timeout here is somewhat arbitrary.
99051974Smsmith	 */
99151974Smsmith	amr_done(sc);
99265245Smsmith	DELAY(1000);
99365245Smsmith    } while ((ac->ac_flags & AMR_CMD_BUSY) && (count++ < 1000));
99465245Smsmith    if (!(ac->ac_flags & AMR_CMD_BUSY)) {
99551974Smsmith	error = 0;
99651974Smsmith    } else {
99765245Smsmith	/* XXX the slot is now marked permanently busy */
99851974Smsmith	error = EIO;
99965245Smsmith	device_printf(sc->amr_dev, "polled command timeout\n");
100051974Smsmith    }
100151974Smsmith    return(error);
100251974Smsmith}
100351974Smsmith
1004138422Sscottlstatic void
1005138422Sscottlamr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
1006138422Sscottl{
1007138422Sscottl    struct amr_command *ac = arg;
1008138422Sscottl    struct amr_softc *sc = ac->ac_sc;
1009138422Sscottl
1010138422Sscottl    amr_setup_dmamap(arg, segs, nsegs, err);
1011138422Sscottl    bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
1012138422Sscottl    sc->amr_poll_command1(sc, ac);
1013138422Sscottl}
1014138422Sscottl
101551974Smsmith/********************************************************************************
1016107756Semoore * Take a command, submit it to the controller and busy-wait for it to return.
1017107756Semoore * Returns nonzero on error.  Can be safely called with interrupts enabled.
1018107756Semoore */
1019107756Semoorestatic int
1020107756Semooreamr_quartz_poll_command(struct amr_command *ac)
1021107756Semoore{
1022107756Semoore    struct amr_softc	*sc = ac->ac_sc;
1023138422Sscottl    int			s, error;
1024107756Semoore
1025107756Semoore    debug_called(2);
1026107756Semoore
1027138422Sscottl    s = splbio();
1028138422Sscottl    error = 0;
1029138422Sscottl
1030107756Semoore    /* now we have a slot, we can map the command (unmapped in amr_complete) */
1031138422Sscottl    if (ac->ac_data != 0) {
1032138422Sscottl	if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1033138422Sscottl	    ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) {
1034138422Sscottl	    error = 1;
1035138422Sscottl	}
1036138422Sscottl    } else {
1037138422Sscottl	error = amr_quartz_poll_command1(sc, ac);
1038138422Sscottl    }
1039107756Semoore
1040138422Sscottl    splx(s);
1041138422Sscottl    return (error);
1042138422Sscottl}
1043107756Semoore
1044138422Sscottlstatic int
1045138422Sscottlamr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac)
1046138422Sscottl{
1047138422Sscottl    int count, error;
1048138422Sscottl
1049131394Sps    if ((sc->amr_state & AMR_STATE_CRASHDUMP) == 0) {
1050120988Sps	count=0;
1051120988Sps	while (sc->amr_busyslots) {
1052120988Sps	    tsleep(sc, PRIBIO | PCATCH, "amrpoll", hz);
1053120988Sps	    if(count++>10) {
1054120988Sps		break;
1055120988Sps	    }
1056109031Semoore	}
1057109031Semoore
1058120988Sps	if(sc->amr_busyslots) {
1059120988Sps	    device_printf(sc->amr_dev, "adapter is busy\n");
1060138422Sscottl	    if (ac->ac_data != NULL)
1061138422Sscottl		bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
1062120988Sps    	    ac->ac_status=0;
1063120988Sps	    return(1);
1064120988Sps	}
1065107756Semoore    }
1066107756Semoore
1067107756Semoore    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
1068107756Semoore
1069107756Semoore    /* clear the poll/ack fields in the mailbox */
1070107756Semoore    sc->amr_mailbox->mb_ident = 0xFE;
1071107756Semoore    sc->amr_mailbox->mb_nstatus = 0xFF;
1072107756Semoore    sc->amr_mailbox->mb_status = 0xFF;
1073107756Semoore    sc->amr_mailbox->mb_poll = 0;
1074107756Semoore    sc->amr_mailbox->mb_ack = 0;
1075109031Semoore    sc->amr_mailbox->mb_busy = 1;
1076107756Semoore
1077107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
1078107756Semoore
1079107756Semoore    while(sc->amr_mailbox->mb_nstatus == 0xFF);
1080107756Semoore    while(sc->amr_mailbox->mb_status == 0xFF);
1081107827Semoore    ac->ac_status=sc->amr_mailbox->mb_status;
1082107827Semoore    error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0;
1083107756Semoore    while(sc->amr_mailbox->mb_poll != 0x77);
1084107756Semoore    sc->amr_mailbox->mb_poll = 0;
1085107756Semoore    sc->amr_mailbox->mb_ack = 0x77;
1086107756Semoore
1087107756Semoore    /* acknowledge that we have the commands */
1088107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
1089109031Semoore    while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK);
1090107756Semoore
1091107756Semoore    /* unmap the command's data buffer */
1092138422Sscottl    bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD);
1093138422Sscottl    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
1094107756Semoore
1095107827Semoore    return(error);
1096107756Semoore}
1097107756Semoore
1098107756Semoore/********************************************************************************
109965245Smsmith * Get a free command slot for a command if it doesn't already have one.
110065245Smsmith *
110165245Smsmith * May be safely called multiple times for a given command.
110251974Smsmith */
110351974Smsmithstatic int
110451974Smsmithamr_getslot(struct amr_command *ac)
110551974Smsmith{
110651974Smsmith    struct amr_softc	*sc = ac->ac_sc;
110765245Smsmith    int			s, slot, limit, error;
110851974Smsmith
110965245Smsmith    debug_called(3);
111065245Smsmith
111165245Smsmith    /* if the command already has a slot, don't try to give it another one */
111265245Smsmith    if (ac->ac_slot != 0)
111365245Smsmith	return(0);
111465245Smsmith
111551974Smsmith    /* enforce slot usage limit */
111651974Smsmith    limit = (ac->ac_flags & AMR_CMD_PRIORITY) ? sc->amr_maxio : sc->amr_maxio - 4;
111765245Smsmith    if (sc->amr_busyslots > limit)
111851974Smsmith	return(EBUSY);
111951974Smsmith
112051974Smsmith    /*
112165245Smsmith     * Allocate a slot.  XXX linear scan is slow
112251974Smsmith     */
112365245Smsmith    error = EBUSY;
112451974Smsmith    s = splbio();
112551974Smsmith    for (slot = 0; slot < sc->amr_maxio; slot++) {
112665245Smsmith	if (sc->amr_busycmd[slot] == NULL) {
112765245Smsmith	    sc->amr_busycmd[slot] = ac;
112865245Smsmith	    sc->amr_busyslots++;
112965245Smsmith	    ac->ac_slot = slot;
113065245Smsmith	    error = 0;
113151974Smsmith	    break;
113265245Smsmith	}
113351974Smsmith    }
113451974Smsmith    splx(s);
113551974Smsmith
113665245Smsmith    return(error);
113751974Smsmith}
113851974Smsmith
113951974Smsmith/********************************************************************************
114065245Smsmith * Map/unmap (ac)'s data in the controller's addressable space as required.
114165245Smsmith *
114265245Smsmith * These functions may be safely called multiple times on a given command.
114351974Smsmith */
114451974Smsmithstatic void
114551974Smsmithamr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
114651974Smsmith{
114751974Smsmith    struct amr_command	*ac = (struct amr_command *)arg;
114851974Smsmith    struct amr_softc	*sc = ac->ac_sc;
114951974Smsmith    struct amr_sgentry	*sg;
115051974Smsmith    int			i;
115169319Smsmith    u_int8_t		*sgc;
115251974Smsmith
115365245Smsmith    debug_called(3);
115451974Smsmith
115551974Smsmith    /* get base address of s/g table */
115651974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
115751974Smsmith
115865245Smsmith    /* save data physical address */
115951974Smsmith    ac->ac_dataphys = segs[0].ds_addr;
116051974Smsmith
116169319Smsmith    /* for AMR_CMD_CONFIG the s/g count goes elsewhere */
116269319Smsmith    if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) {
116369319Smsmith	sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
116469319Smsmith    } else {
116569319Smsmith	sgc = &ac->ac_mailbox.mb_nsgelem;
116669319Smsmith    }
116769319Smsmith
116865245Smsmith    /* decide whether we need to populate the s/g table */
116965245Smsmith    if (nsegments < 2) {
117069319Smsmith	*sgc = 0;
1171105419Semoore	ac->ac_mailbox.mb_nsgelem = 0;
117265245Smsmith	ac->ac_mailbox.mb_physaddr = ac->ac_dataphys;
117365245Smsmith    } else {
1174105419Semoore        ac->ac_mailbox.mb_nsgelem = nsegments;
117569319Smsmith	*sgc = nsegments;
1176138422Sscottl	ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr +
1177138422Sscottl	    (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
117865245Smsmith	for (i = 0; i < nsegments; i++, sg++) {
117965245Smsmith	    sg->sg_addr = segs[i].ds_addr;
118065245Smsmith	    sg->sg_count = segs[i].ds_len;
118165245Smsmith	}
118265245Smsmith    }
1183138422Sscottl
118465245Smsmith}
118565245Smsmith
118665245Smsmithstatic void
118765245Smsmithamr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
118865245Smsmith{
1189105419Semoore    struct amr_command          *ac = (struct amr_command *)arg;
1190105419Semoore    struct amr_softc            *sc = ac->ac_sc;
1191105419Semoore    struct amr_sgentry          *sg;
1192105419Semoore    struct amr_passthrough      *ap = (struct amr_passthrough *)ac->ac_data;
1193106252Semoore    struct amr_ext_passthrough	*aep = (struct amr_ext_passthrough *)ac->ac_data;
1194105419Semoore    int                         i;
119565245Smsmith
119665245Smsmith    /* get base address of s/g table */
119765245Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
119865245Smsmith
1199105419Semoore    /* decide whether we need to populate the s/g table */
1200106225Semoore    if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
1201106225Semoore	if (nsegments < 2) {
1202106225Semoore	    aep->ap_no_sg_elements = 0;
1203106225Semoore	    aep->ap_data_transfer_address =  segs[0].ds_addr;
1204106225Semoore	} else {
1205106225Semoore	    /* save s/g table information in passthrough */
1206106225Semoore	    aep->ap_no_sg_elements = nsegments;
1207138422Sscottl	    aep->ap_data_transfer_address = sc->amr_sgbusaddr +
1208138422Sscottl		(ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1209138422Sscottl	    /*
1210138422Sscottl	     * populate s/g table (overwrites previous call which mapped the
1211138422Sscottl	     * passthrough)
1212138422Sscottl	     */
1213106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1214106225Semoore		sg->sg_addr = segs[i].ds_addr;
1215106225Semoore		sg->sg_count = segs[i].ds_len;
1216106225Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1217106225Semoore	    }
1218106225Semoore	}
1219138422Sscottl	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x\n",
1220138422Sscottl	    ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address,
1221138422Sscottl	    ac->ac_dataphys);
1222105419Semoore    } else {
1223106225Semoore	if (nsegments < 2) {
1224106225Semoore	    ap->ap_no_sg_elements = 0;
1225106225Semoore	    ap->ap_data_transfer_address =  segs[0].ds_addr;
1226106225Semoore	} else {
1227106225Semoore	    /* save s/g table information in passthrough */
1228106225Semoore	    ap->ap_no_sg_elements = nsegments;
1229138422Sscottl	    ap->ap_data_transfer_address = sc->amr_sgbusaddr +
1230138422Sscottl		(ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1231138422Sscottl	    /*
1232138422Sscottl	     * populate s/g table (overwrites previous call which mapped the
1233138422Sscottl	     * passthrough)
1234138422Sscottl	     */
1235106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1236105419Semoore		sg->sg_addr = segs[i].ds_addr;
1237105419Semoore		sg->sg_count = segs[i].ds_len;
1238105419Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1239106225Semoore	    }
1240105419Semoore	}
1241138422Sscottl	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x",
1242138422Sscottl	    ac->ac_slot, ap->ap_no_sg_elements, ap->ap_data_transfer_address,
1243138422Sscottl	    ac->ac_dataphys);
1244105419Semoore    }
1245138422Sscottl    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
1246138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1247138422Sscottl	    BUS_DMASYNC_PREREAD);
1248138422Sscottl    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
1249138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1250138422Sscottl	    BUS_DMASYNC_PREWRITE);
1251138422Sscottl    if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0)
1252138422Sscottl	panic("no direction for ccb?\n");
1253138422Sscottl
1254138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAIN)
1255138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
1256138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAOUT)
1257138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE);
1258138422Sscottl
1259138422Sscottl    ac->ac_flags |= AMR_CMD_MAPPED;
1260138422Sscottl
1261138422Sscottl    amr_start1(sc, ac);
126251974Smsmith}
126351974Smsmith
1264138422Sscottlstatic int
126551974Smsmithamr_mapcmd(struct amr_command *ac)
126651974Smsmith{
126751974Smsmith    struct amr_softc	*sc = ac->ac_sc;
126851974Smsmith
126969319Smsmith    debug_called(3);
127051974Smsmith
127165245Smsmith    /* if the command involves data at all, and hasn't been mapped */
1272138422Sscottl    if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) {
1273138422Sscottl	if (ac->ac_ccb_data == NULL) {
127465245Smsmith	    /* map the data buffers into bus space and build the s/g list */
1275138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1276138422Sscottl		ac->ac_length, amr_setup_data_dmamap, ac, 0) == EINPROGRESS) {
1277138422Sscottl		sc->amr_state |= AMR_STATE_QUEUE_FRZN;
1278138422Sscottl	    }
1279138422Sscottl	} else {
128065245Smsmith
1281138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1282138422Sscottl		ac->ac_length, amr_setup_dmamap, ac, BUS_DMA_NOWAIT) != 0){
1283138422Sscottl		return (ENOMEM);
1284138422Sscottl	    }
1285138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1286138422Sscottl		ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac,
1287138422Sscottl		0) == EINPROGRESS) {
1288138422Sscottl		sc->amr_state |= AMR_STATE_QUEUE_FRZN;
1289138422Sscottl	    }
129065245Smsmith	}
129151974Smsmith    }
1292138422Sscottl    return (0);
129351974Smsmith}
129451974Smsmith
129551974Smsmithstatic void
129651974Smsmithamr_unmapcmd(struct amr_command *ac)
129751974Smsmith{
129851974Smsmith    struct amr_softc	*sc = ac->ac_sc;
129951974Smsmith
130069319Smsmith    debug_called(3);
130151974Smsmith
130265245Smsmith    /* if the command involved data at all and was mapped */
130365245Smsmith    if (ac->ac_flags & AMR_CMD_MAPPED) {
130451974Smsmith
130565245Smsmith	if (ac->ac_data != NULL) {
130665245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAIN)
1307138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap,
1308138422Sscottl		    BUS_DMASYNC_POSTREAD);
130965245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAOUT)
1310138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap,
1311138422Sscottl		    BUS_DMASYNC_POSTWRITE);
131265245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
131365245Smsmith	}
131465245Smsmith
131565245Smsmith	if (ac->ac_ccb_data != NULL) {
131665245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
1317138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1318138422Sscottl		    BUS_DMASYNC_POSTREAD);
131965245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
1320138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1321138422Sscottl		    BUS_DMASYNC_POSTWRITE);
132265245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap);
1323138422Sscottl	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x\n",
1324138422Sscottl	    ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address,
1325138422Sscottl	    ac->ac_dataphys);
132665245Smsmith	}
132765245Smsmith	ac->ac_flags &= ~AMR_CMD_MAPPED;
132851974Smsmith    }
132951974Smsmith}
133051974Smsmith
1331138422Sscottlstatic void
1332138422Sscottlamr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
1333138422Sscottl{
1334138422Sscottl    struct amr_command *ac = arg;
1335138422Sscottl    struct amr_softc *sc = ac->ac_sc;
1336138422Sscottl
1337138422Sscottl    amr_setup_dmamap(arg, segs, nsegs, err);
1338138422Sscottl
1339138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAIN)
1340138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
1341138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAOUT)
1342138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE);
1343138422Sscottl    ac->ac_flags |= AMR_CMD_MAPPED;
1344138422Sscottl
1345138422Sscottl    amr_start1(sc, ac);
1346138422Sscottl}
1347138422Sscottl
134851974Smsmith/********************************************************************************
134965245Smsmith * Take a command and give it to the controller, returns 0 if successful, or
135065245Smsmith * EBUSY if the command should be retried later.
135151974Smsmith */
135251974Smsmithstatic int
135351974Smsmithamr_start(struct amr_command *ac)
135451974Smsmith{
1355138422Sscottl    struct amr_softc *sc;
1356138422Sscottl    int error = 0;
1357105419Semoore
135869319Smsmith    debug_called(3);
135951974Smsmith
136065245Smsmith    /* mark command as busy so that polling consumer can tell */
1361138422Sscottl    sc = ac->ac_sc;
136265245Smsmith    ac->ac_flags |= AMR_CMD_BUSY;
136365245Smsmith
136465245Smsmith    /* get a command slot (freed in amr_done) */
136565245Smsmith    if (amr_getslot(ac))
136665245Smsmith	return(EBUSY);
136765245Smsmith
1368138422Sscottl    /* Now we have a slot, we can map the command (unmapped in amr_complete). */
1369138422Sscottl    if ((error = amr_mapcmd(ac)) == ENOMEM) {
1370138422Sscottl	/*
1371138422Sscottl	 * Memroy resources are short, so free the slot and let this be tried
1372138422Sscottl	 * later.
1373138422Sscottl	 */
1374138422Sscottl	sc->amr_busycmd[ac->ac_slot] = NULL;
1375138422Sscottl	sc->amr_busyslots--;
1376138422Sscottl    }
137765245Smsmith
1378138422Sscottl    return (error);
1379138422Sscottl}
1380138422Sscottl
1381138422Sscottl
1382138422Sscottlstatic int
1383138422Sscottlamr_start1(struct amr_softc *sc, struct amr_command *ac)
1384138422Sscottl{
1385138422Sscottl    int			done, s, i;
1386138422Sscottl
138765245Smsmith    /* mark the new mailbox we are going to copy in as busy */
138865245Smsmith    ac->ac_mailbox.mb_busy = 1;
138965245Smsmith
139065245Smsmith    /* clear the poll/ack fields in the mailbox */
139165245Smsmith    sc->amr_mailbox->mb_poll = 0;
139265245Smsmith    sc->amr_mailbox->mb_ack = 0;
139365245Smsmith
139451974Smsmith    /*
139551974Smsmith     * Save the slot number so that we can locate this command when complete.
139651974Smsmith     * Note that ident = 0 seems to be special, so we don't use it.
139751974Smsmith     */
139851974Smsmith    ac->ac_mailbox.mb_ident = ac->ac_slot + 1;
139951974Smsmith
140058883Smsmith    /*
140165245Smsmith     * Spin waiting for the mailbox, give up after ~1 second.  We expect the
140265245Smsmith     * controller to be able to handle our I/O.
140365245Smsmith     *
140465245Smsmith     * XXX perhaps we should wait for less time, and count on the deferred command
140565245Smsmith     * handling to deal with retries?
140658883Smsmith     */
140769319Smsmith    debug(4, "wait for mailbox");
140858883Smsmith    for (i = 10000, done = 0; (i > 0) && !done; i--) {
140951974Smsmith	s = splbio();
141051974Smsmith
141151974Smsmith	/* is the mailbox free? */
141251974Smsmith	if (sc->amr_mailbox->mb_busy == 0) {
141369319Smsmith	    debug(4, "got mailbox");
141451974Smsmith	    sc->amr_mailbox64->mb64_segment = 0;
141565245Smsmith	    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
141651974Smsmith	    done = 1;
141751974Smsmith
141865245Smsmith	    /* not free, spin waiting */
141951974Smsmith	} else {
142069319Smsmith	    debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy);
142158883Smsmith	    /* this is somewhat ugly */
142258883Smsmith	    DELAY(100);
142351974Smsmith	}
142458883Smsmith	splx(s);	/* drop spl to allow completion interrupts */
142551974Smsmith    }
142665245Smsmith
142765245Smsmith    /*
142865245Smsmith     * Now give the command to the controller
142965245Smsmith     */
143051974Smsmith    if (done) {
143165245Smsmith	if (sc->amr_submit_command(sc)) {
143265245Smsmith	    /* the controller wasn't ready to take the command, forget that we tried to post it */
143365245Smsmith	    sc->amr_mailbox->mb_busy = 0;
143465245Smsmith	    return(EBUSY);
143565245Smsmith	}
143669319Smsmith	debug(3, "posted command");
143751974Smsmith	return(0);
143851974Smsmith    }
143951974Smsmith
144051974Smsmith    /*
144165245Smsmith     * The controller wouldn't take the command.  Return the command as busy
144265245Smsmith     * so that it is retried later.
144351974Smsmith     */
144465245Smsmith    return(EBUSY);
144551974Smsmith}
144651974Smsmith
144751974Smsmith/********************************************************************************
144851974Smsmith * Extract one or more completed commands from the controller (sc)
144951974Smsmith *
145052543Smsmith * Returns nonzero if any commands on the work queue were marked as completed.
145151974Smsmith */
145265245Smsmithint
145351974Smsmithamr_done(struct amr_softc *sc)
145451974Smsmith{
145551974Smsmith    struct amr_command	*ac;
145651974Smsmith    struct amr_mailbox	mbox;
145765245Smsmith    int			i, idx, result;
145851974Smsmith
145969319Smsmith    debug_called(3);
146051974Smsmith
146151974Smsmith    /* See if there's anything for us to do */
146251974Smsmith    result = 0;
146351974Smsmith
146458883Smsmith    /* loop collecting completed commands */
146558883Smsmith    for (;;) {
146658883Smsmith	/* poll for a completed command's identifier and status */
146758883Smsmith	if (sc->amr_get_work(sc, &mbox)) {
146858883Smsmith	    result = 1;
146958883Smsmith
147058883Smsmith	    /* iterate over completed commands in this result */
147158883Smsmith	    for (i = 0; i < mbox.mb_nstatus; i++) {
147258883Smsmith		/* get pointer to busy command */
147358883Smsmith		idx = mbox.mb_completed[i] - 1;
147458883Smsmith		ac = sc->amr_busycmd[idx];
147551974Smsmith
147658883Smsmith		/* really a busy command? */
147758883Smsmith		if (ac != NULL) {
147858883Smsmith
147958883Smsmith		    /* pull the command from the busy index */
148058883Smsmith		    sc->amr_busycmd[idx] = NULL;
148165245Smsmith		    sc->amr_busyslots--;
148251974Smsmith
148365245Smsmith		    /* save status for later use */
148465245Smsmith		    ac->ac_status = mbox.mb_status;
148565245Smsmith		    amr_enqueue_completed(ac);
148665245Smsmith		    debug(3, "completed command with status %x", mbox.mb_status);
148765245Smsmith		} else {
148865245Smsmith		    device_printf(sc->amr_dev, "bad slot %d completed\n", idx);
148951974Smsmith		}
149051974Smsmith	    }
149158883Smsmith	} else {
149265245Smsmith	    break;	/* no work */
149351974Smsmith	}
149451974Smsmith    }
1495138422Sscottl
149658883Smsmith    /* if we've completed any commands, try posting some more */
1497138422Sscottl    sc->amr_state &= ~AMR_STATE_QUEUE_FRZN;
149858883Smsmith    if (result)
149958883Smsmith	amr_startio(sc);
150058883Smsmith
150158883Smsmith    /* handle completion and timeouts */
150265245Smsmith#if __FreeBSD_version >= 500005
150365245Smsmith    if (sc->amr_state & AMR_STATE_INTEN)
1504111528Sscottl	taskqueue_enqueue(taskqueue_swi_giant, &sc->amr_task_complete);
150565245Smsmith    else
150665245Smsmith#endif
150765245Smsmith	amr_complete(sc, 0);
1508138422Sscottl
150951974Smsmith    return(result);
151051974Smsmith}
151151974Smsmith
151251974Smsmith/********************************************************************************
151351974Smsmith * Do completion processing on done commands on (sc)
151451974Smsmith */
151551974Smsmithstatic void
151665245Smsmithamr_complete(void *context, int pending)
151751974Smsmith{
151865245Smsmith    struct amr_softc	*sc = (struct amr_softc *)context;
151965245Smsmith    struct amr_command	*ac;
152051974Smsmith
152169319Smsmith    debug_called(3);
152251974Smsmith
152365245Smsmith    /* pull completed commands off the queue */
152465245Smsmith    for (;;) {
152565245Smsmith	ac = amr_dequeue_completed(sc);
152665245Smsmith	if (ac == NULL)
152765245Smsmith	    break;
152858883Smsmith
152965245Smsmith	/* unmap the command's data buffer */
153065245Smsmith	amr_unmapcmd(ac);
153151974Smsmith
153265245Smsmith	/* unbusy the command */
153365245Smsmith	ac->ac_flags &= ~AMR_CMD_BUSY;
153451974Smsmith
153565245Smsmith	/*
153665245Smsmith	 * Is there a completion handler?
153765245Smsmith	 */
153865245Smsmith	if (ac->ac_complete != NULL) {
153965245Smsmith	    ac->ac_complete(ac);
154065245Smsmith
154151974Smsmith	    /*
154265245Smsmith	     * Is someone sleeping on this one?
154351974Smsmith	     */
154465245Smsmith	} else if (ac->ac_flags & AMR_CMD_SLEEP) {
154565245Smsmith	    wakeup(ac);
154651974Smsmith	}
1547109031Semoore
1548109031Semoore	if(!sc->amr_busyslots) {
1549109031Semoore	    wakeup(sc);
1550109031Semoore	}
155151974Smsmith    }
1552138422Sscottl   amr_startio(sc);
155351974Smsmith}
155451974Smsmith
155551974Smsmith/********************************************************************************
155651974Smsmith ********************************************************************************
155751974Smsmith                                                        Command Buffer Management
155851974Smsmith ********************************************************************************
155951974Smsmith ********************************************************************************/
156051974Smsmith
156151974Smsmith/********************************************************************************
156251974Smsmith * Get a new command buffer.
156351974Smsmith *
156451974Smsmith * This may return NULL in low-memory cases.
156551974Smsmith *
156651974Smsmith * If possible, we recycle a command buffer that's been used before.
156751974Smsmith */
156865245Smsmithstruct amr_command *
156951974Smsmithamr_alloccmd(struct amr_softc *sc)
157051974Smsmith{
157151974Smsmith    struct amr_command	*ac;
157251974Smsmith
157365245Smsmith    debug_called(3);
157451974Smsmith
157565245Smsmith    ac = amr_dequeue_free(sc);
157651974Smsmith    if (ac == NULL) {
157765245Smsmith	amr_alloccmd_cluster(sc);
157865245Smsmith	ac = amr_dequeue_free(sc);
157951974Smsmith    }
158065245Smsmith    if (ac == NULL)
158165245Smsmith	return(NULL);
158265245Smsmith
158365245Smsmith    /* clear out significant fields */
158465245Smsmith    ac->ac_slot = 0;
158565245Smsmith    ac->ac_status = 0;
158651974Smsmith    bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox));
158765245Smsmith    ac->ac_flags = 0;
158865245Smsmith    ac->ac_bio = NULL;
158965245Smsmith    ac->ac_data = NULL;
159065245Smsmith    ac->ac_ccb_data = NULL;
159165245Smsmith    ac->ac_complete = NULL;
159251974Smsmith    return(ac);
159351974Smsmith}
159451974Smsmith
159551974Smsmith/********************************************************************************
159651974Smsmith * Release a command buffer for recycling.
159751974Smsmith */
159865245Smsmithvoid
159951974Smsmithamr_releasecmd(struct amr_command *ac)
160051974Smsmith{
160165245Smsmith    debug_called(3);
160251974Smsmith
160365245Smsmith    amr_enqueue_free(ac);
160451974Smsmith}
160551974Smsmith
160651974Smsmith/********************************************************************************
160765245Smsmith * Allocate a new command cluster and initialise it.
160851974Smsmith */
1609104094Sphkstatic void
161065245Smsmithamr_alloccmd_cluster(struct amr_softc *sc)
161151974Smsmith{
161265245Smsmith    struct amr_command_cluster	*acc;
161365245Smsmith    struct amr_command		*ac;
161465245Smsmith    int				s, i;
161551974Smsmith
161665245Smsmith    acc = malloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_NOWAIT);
161765245Smsmith    if (acc != NULL) {
161865245Smsmith	s = splbio();
161965245Smsmith	TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link);
162065245Smsmith	splx(s);
162165245Smsmith	for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
162265245Smsmith	    ac = &acc->acc_command[i];
162365245Smsmith	    bzero(ac, sizeof(*ac));
162465245Smsmith	    ac->ac_sc = sc;
162565245Smsmith	    if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) &&
162665245Smsmith		!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap))
162765245Smsmith		amr_releasecmd(ac);
162865245Smsmith	}
162965245Smsmith    }
163051974Smsmith}
163151974Smsmith
163251974Smsmith/********************************************************************************
163365245Smsmith * Free a command cluster
163465245Smsmith */
1635104094Sphkstatic void
163665245Smsmithamr_freecmd_cluster(struct amr_command_cluster *acc)
163765245Smsmith{
163865245Smsmith    struct amr_softc	*sc = acc->acc_command[0].ac_sc;
163965245Smsmith    int			i;
164065245Smsmith
164165245Smsmith    for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++)
164265245Smsmith	bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap);
164365245Smsmith    free(acc, M_DEVBUF);
164465245Smsmith}
164565245Smsmith
164665245Smsmith/********************************************************************************
164751974Smsmith ********************************************************************************
164851974Smsmith                                                         Interface-specific Shims
164951974Smsmith ********************************************************************************
165051974Smsmith ********************************************************************************/
165151974Smsmith
165251974Smsmith/********************************************************************************
165351974Smsmith * Tell the controller that the mailbox contains a valid command
165451974Smsmith */
165565245Smsmithstatic int
165651974Smsmithamr_quartz_submit_command(struct amr_softc *sc)
165751974Smsmith{
165865245Smsmith    debug_called(3);
165951974Smsmith
166065245Smsmith    if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT)
166165245Smsmith	return(EBUSY);
166251974Smsmith    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
166365245Smsmith    return(0);
166451974Smsmith}
166551974Smsmith
166665245Smsmithstatic int
166751974Smsmithamr_std_submit_command(struct amr_softc *sc)
166851974Smsmith{
166965245Smsmith    debug_called(3);
167051974Smsmith
167165245Smsmith    if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG)
167265245Smsmith	return(EBUSY);
167351974Smsmith    AMR_SPOST_COMMAND(sc);
167465245Smsmith    return(0);
167551974Smsmith}
167651974Smsmith
167751974Smsmith/********************************************************************************
167851974Smsmith * Claim any work that the controller has completed; acknowledge completion,
167951974Smsmith * save details of the completion in (mbsave)
168051974Smsmith */
168151974Smsmithstatic int
168251974Smsmithamr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
168351974Smsmith{
168451974Smsmith    int		s, worked;
168551974Smsmith    u_int32_t	outd;
168651974Smsmith
168765245Smsmith    debug_called(3);
168865245Smsmith
168951974Smsmith    worked = 0;
169051974Smsmith    s = splbio();
169151974Smsmith
169251974Smsmith    /* work waiting for us? */
169351974Smsmith    if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) {
169451974Smsmith
169551974Smsmith	/* save mailbox, which contains a list of completed commands */
169665245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
169751974Smsmith
169865245Smsmith	/* acknowledge interrupt */
169965245Smsmith	AMR_QPUT_ODB(sc, AMR_QODB_READY);
170065245Smsmith
170151974Smsmith	/* acknowledge that we have the commands */
170251974Smsmith	AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
170365245Smsmith
170465763Smsmith#ifndef AMR_QUARTZ_GOFASTER
170565245Smsmith	/*
170665245Smsmith	 * This waits for the controller to notice that we've taken the
170765245Smsmith	 * command from it.  It's very inefficient, and we shouldn't do it,
170865245Smsmith	 * but if we remove this code, we stop completing commands under
170965245Smsmith	 * load.
171065245Smsmith	 *
171165245Smsmith	 * Peter J says we shouldn't do this.  The documentation says we
171265245Smsmith	 * should.  Who is right?
171365245Smsmith	 */
171451974Smsmith	while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
171551974Smsmith	    ;				/* XXX aiee! what if it dies? */
171665245Smsmith#endif
171765245Smsmith
171851974Smsmith	worked = 1;			/* got some work */
171951974Smsmith    }
172051974Smsmith
172151974Smsmith    splx(s);
172251974Smsmith    return(worked);
172351974Smsmith}
172451974Smsmith
172551974Smsmithstatic int
172651974Smsmithamr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
172751974Smsmith{
172851974Smsmith    int		s, worked;
172951974Smsmith    u_int8_t	istat;
173051974Smsmith
173165245Smsmith    debug_called(3);
173251974Smsmith
173351974Smsmith    worked = 0;
173451974Smsmith    s = splbio();
173551974Smsmith
173651974Smsmith    /* check for valid interrupt status */
173751974Smsmith    istat = AMR_SGET_ISTAT(sc);
173851974Smsmith    if ((istat & AMR_SINTR_VALID) != 0) {
173951974Smsmith	AMR_SPUT_ISTAT(sc, istat);	/* ack interrupt status */
174051974Smsmith
174151974Smsmith	/* save mailbox, which contains a list of completed commands */
174265245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
174351974Smsmith
174451974Smsmith	AMR_SACK_INTERRUPT(sc);		/* acknowledge we have the mailbox */
174551974Smsmith	worked = 1;
174651974Smsmith    }
174751974Smsmith
174851974Smsmith    splx(s);
174951974Smsmith    return(worked);
175051974Smsmith}
175151974Smsmith
175251974Smsmith/********************************************************************************
175351974Smsmith * Notify the controller of the mailbox location.
175451974Smsmith */
175551974Smsmithstatic void
175651974Smsmithamr_std_attach_mailbox(struct amr_softc *sc)
175751974Smsmith{
175851974Smsmith
175951974Smsmith    /* program the mailbox physical address */
176051974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_0, sc->amr_mailboxphys         & 0xff);
176151974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_1, (sc->amr_mailboxphys >>  8) & 0xff);
176251974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_2, (sc->amr_mailboxphys >> 16) & 0xff);
176351974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_3, (sc->amr_mailboxphys >> 24) & 0xff);
176451974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_ENABLE, AMR_SMBOX_ADDR);
176551974Smsmith
176651974Smsmith    /* clear any outstanding interrupt and enable interrupts proper */
176751974Smsmith    AMR_SACK_INTERRUPT(sc);
176851974Smsmith    AMR_SENABLE_INTR(sc);
176951974Smsmith}
177051974Smsmith
177165245Smsmith#ifdef AMR_BOARD_INIT
177251974Smsmith/********************************************************************************
177365245Smsmith * Initialise the controller
177465245Smsmith */
177565245Smsmithstatic int
177665245Smsmithamr_quartz_init(struct amr_softc *sc)
177765245Smsmith{
177865245Smsmith    int		status, ostatus;
177965245Smsmith
178065245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_QGET_INITSTATUS(sc));
178165245Smsmith
178265245Smsmith    AMR_QRESET(sc);
178365245Smsmith
178465245Smsmith    ostatus = 0xff;
178565245Smsmith    while ((status = AMR_QGET_INITSTATUS(sc)) != AMR_QINIT_DONE) {
178665245Smsmith	if (status != ostatus) {
178765245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_qinit, status));
178865245Smsmith	    ostatus = status;
178965245Smsmith	}
179065245Smsmith	switch (status) {
179165245Smsmith	case AMR_QINIT_NOMEM:
179265245Smsmith	    return(ENOMEM);
179365245Smsmith
179465245Smsmith	case AMR_QINIT_SCAN:
179565245Smsmith	    /* XXX we could print channel/target here */
179665245Smsmith	    break;
179765245Smsmith	}
179865245Smsmith    }
179965245Smsmith    return(0);
180065245Smsmith}
180165245Smsmith
180265245Smsmithstatic int
180365245Smsmithamr_std_init(struct amr_softc *sc)
180465245Smsmith{
180565245Smsmith    int		status, ostatus;
180665245Smsmith
180765245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_SGET_INITSTATUS(sc));
180865245Smsmith
180965245Smsmith    AMR_SRESET(sc);
181065245Smsmith
181165245Smsmith    ostatus = 0xff;
181265245Smsmith    while ((status = AMR_SGET_INITSTATUS(sc)) != AMR_SINIT_DONE) {
181365245Smsmith	if (status != ostatus) {
181465245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_sinit, status));
181565245Smsmith	    ostatus = status;
181665245Smsmith	}
181765245Smsmith	switch (status) {
181865245Smsmith	case AMR_SINIT_NOMEM:
181965245Smsmith	    return(ENOMEM);
182065245Smsmith
182165245Smsmith	case AMR_SINIT_INPROG:
182265245Smsmith	    /* XXX we could print channel/target here? */
182365245Smsmith	    break;
182465245Smsmith	}
182565245Smsmith    }
182665245Smsmith    return(0);
182765245Smsmith}
182865245Smsmith#endif
182965245Smsmith
183065245Smsmith/********************************************************************************
183151974Smsmith ********************************************************************************
183251974Smsmith                                                                        Debugging
183351974Smsmith ********************************************************************************
183451974Smsmith ********************************************************************************/
183551974Smsmith
183651974Smsmith/********************************************************************************
183765245Smsmith * Identify the controller and print some information about it.
183865245Smsmith */
183965245Smsmithstatic void
184065245Smsmithamr_describe_controller(struct amr_softc *sc)
184165245Smsmith{
184265245Smsmith    struct amr_prodinfo	*ap;
184365245Smsmith    struct amr_enquiry	*ae;
184465245Smsmith    char		*prod;
184565245Smsmith
184665245Smsmith    /*
184765245Smsmith     * Try to get 40LD product info, which tells us what the card is labelled as.
184865245Smsmith     */
184965245Smsmith    if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) {
1850105419Semoore	device_printf(sc->amr_dev, "<LSILogic %.80s> Firmware %.16s, BIOS %.16s, %dMB RAM\n",
185165245Smsmith		      ap->ap_product, ap->ap_firmware, ap->ap_bios,
185265245Smsmith		      ap->ap_memsize);
185365245Smsmith
185465245Smsmith	free(ap, M_DEVBUF);
185565245Smsmith	return;
185665245Smsmith    }
185765245Smsmith
185865245Smsmith    /*
185965245Smsmith     * Try 8LD extended ENQUIRY to get controller signature, and use lookup table.
186065245Smsmith     */
186165245Smsmith    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) {
186265245Smsmith	prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature);
186365245Smsmith
186465245Smsmith    } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) {
186565245Smsmith
186665245Smsmith	/*
186765245Smsmith	 * Try to work it out based on the PCI signatures.
186865245Smsmith	 */
186965245Smsmith	switch (pci_get_device(sc->amr_dev)) {
187065245Smsmith	case 0x9010:
187165245Smsmith	    prod = "Series 428";
187265245Smsmith	    break;
187365245Smsmith	case 0x9060:
187465245Smsmith	    prod = "Series 434";
187565245Smsmith	    break;
187665245Smsmith	default:
187765245Smsmith	    prod = "unknown controller";
187865245Smsmith	    break;
187965245Smsmith	}
188065245Smsmith    } else {
188165245Smsmith	prod = "unsupported controller";
188265245Smsmith    }
188374936Shm
188474936Shm    /*
188574936Shm     * HP NetRaid controllers have a special encoding of the firmware and
188674936Shm     * BIOS versions. The AMI version seems to have it as strings whereas
188774936Shm     * the HP version does it with a leading uppercase character and two
188874936Shm     * binary numbers.
188974936Shm     */
189074936Shm
189174936Shm    if(ae->ae_adapter.aa_firmware[2] >= 'A' &&
189274936Shm       ae->ae_adapter.aa_firmware[2] <= 'Z' &&
189374936Shm       ae->ae_adapter.aa_firmware[1] <  ' ' &&
189474936Shm       ae->ae_adapter.aa_firmware[0] <  ' ' &&
189574936Shm       ae->ae_adapter.aa_bios[2] >= 'A'     &&
189674936Shm       ae->ae_adapter.aa_bios[2] <= 'Z'     &&
189774936Shm       ae->ae_adapter.aa_bios[1] <  ' '     &&
189874936Shm       ae->ae_adapter.aa_bios[0] <  ' ') {
189974936Shm
190074936Shm	/* this looks like we have an HP NetRaid version of the MegaRaid */
190174936Shm
190274936Shm    	if(ae->ae_signature == AMR_SIG_438) {
1903108470Sschweikh    		/* the AMI 438 is a NetRaid 3si in HP-land */
190474936Shm    		prod = "HP NetRaid 3si";
190574936Shm    	}
190674936Shm
190774936Shm	device_printf(sc->amr_dev, "<%s> Firmware %c.%02d.%02d, BIOS %c.%02d.%02d, %dMB RAM\n",
190874936Shm		      prod, ae->ae_adapter.aa_firmware[2],
190974936Shm		      ae->ae_adapter.aa_firmware[1],
191074936Shm		      ae->ae_adapter.aa_firmware[0],
191174936Shm		      ae->ae_adapter.aa_bios[2],
191274936Shm		      ae->ae_adapter.aa_bios[1],
191374936Shm		      ae->ae_adapter.aa_bios[0],
191474936Shm		      ae->ae_adapter.aa_memorysize);
191574936Shm    } else {
191674936Shm	device_printf(sc->amr_dev, "<%s> Firmware %.4s, BIOS %.4s, %dMB RAM\n",
191774936Shm		      prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios,
191874936Shm		      ae->ae_adapter.aa_memorysize);
191974936Shm    }
192065245Smsmith    free(ae, M_DEVBUF);
192165245Smsmith}
192265245Smsmith
1923120988Spsint
1924120988Spsamr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks)
1925120988Sps{
1926120988Sps    struct amr_command	*ac;
1927120988Sps    int			error = EIO;
1928120988Sps
1929120988Sps    debug_called(1);
1930120988Sps
1931131394Sps    sc->amr_state |= AMR_STATE_CRASHDUMP;
1932120988Sps
1933120988Sps    /* get ourselves a command buffer */
1934120988Sps    if ((ac = amr_alloccmd(sc)) == NULL)
1935120988Sps	goto out;
1936120988Sps    /* set command flags */
1937120988Sps    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
1938120988Sps
1939120988Sps    /* point the command at our data */
1940120988Sps    ac->ac_data = data;
1941120988Sps    ac->ac_length = blks * AMR_BLKSIZE;
1942120988Sps
1943120988Sps    /* build the command proper */
1944120988Sps    ac->ac_mailbox.mb_command 	= AMR_CMD_LWRITE;
1945120988Sps    ac->ac_mailbox.mb_blkcount	= blks;
1946120988Sps    ac->ac_mailbox.mb_lba	= lba;
1947120988Sps    ac->ac_mailbox.mb_drive	= unit;
1948120988Sps
1949120988Sps    /* can't assume that interrupts are going to work here, so play it safe */
1950120988Sps    if (sc->amr_poll_command(ac))
1951120988Sps	goto out;
1952120988Sps    error = ac->ac_status;
1953120988Sps
1954120988Sps out:
1955120988Sps    if (ac != NULL)
1956120988Sps	amr_releasecmd(ac);
1957120988Sps
1958131394Sps    sc->amr_state &= ~AMR_STATE_CRASHDUMP;
1959120988Sps    return (error);
1960120988Sps}
1961120988Sps
1962120988Sps
1963120988Sps
196465245Smsmith#ifdef AMR_DEBUG
196565245Smsmith/********************************************************************************
196651974Smsmith * Print the command (ac) in human-readable format
196751974Smsmith */
1968107756Semoore#if 0
196951974Smsmithstatic void
197051974Smsmithamr_printcommand(struct amr_command *ac)
197151974Smsmith{
197251974Smsmith    struct amr_softc	*sc = ac->ac_sc;
197351974Smsmith    struct amr_sgentry	*sg;
197451974Smsmith    int			i;
197551974Smsmith
197651974Smsmith    device_printf(sc->amr_dev, "cmd %x  ident %d  drive %d\n",
197751974Smsmith		  ac->ac_mailbox.mb_command, ac->ac_mailbox.mb_ident, ac->ac_mailbox.mb_drive);
197851974Smsmith    device_printf(sc->amr_dev, "blkcount %d  lba %d\n",
197951974Smsmith		  ac->ac_mailbox.mb_blkcount, ac->ac_mailbox.mb_lba);
198054512Speter    device_printf(sc->amr_dev, "virtaddr %p  length %lu\n", ac->ac_data, (unsigned long)ac->ac_length);
198158883Smsmith    device_printf(sc->amr_dev, "sg physaddr %08x  nsg %d\n",
198251974Smsmith		  ac->ac_mailbox.mb_physaddr, ac->ac_mailbox.mb_nsgelem);
198365245Smsmith    device_printf(sc->amr_dev, "ccb %p  bio %p\n", ac->ac_ccb_data, ac->ac_bio);
198451974Smsmith
198551974Smsmith    /* get base address of s/g table */
198651974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
198751974Smsmith    for (i = 0; i < ac->ac_mailbox.mb_nsgelem; i++, sg++)
198851974Smsmith	device_printf(sc->amr_dev, "  %x/%d\n", sg->sg_addr, sg->sg_count);
198951974Smsmith}
199065245Smsmith#endif
1991107756Semoore#endif
1992