amr.c revision 133870
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 133870 2004-08-16 17:23:09Z ambrisko $");
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);
12665245Smsmithstatic int	amr_wait_command(struct amr_command *ac);
12765245Smsmithstatic int	amr_getslot(struct amr_command *ac);
12865245Smsmithstatic void	amr_mapcmd(struct amr_command *ac);
12965245Smsmithstatic void	amr_unmapcmd(struct amr_command *ac);
13065245Smsmithstatic int	amr_start(struct amr_command *ac);
13165245Smsmithstatic void	amr_complete(void *context, int pending);
13251974Smsmith
13351974Smsmith/*
13458883Smsmith * Status monitoring
13558883Smsmith */
13665245Smsmithstatic void	amr_periodic(void *data);
13758883Smsmith
13858883Smsmith/*
13951974Smsmith * Interface-specific shims
14051974Smsmith */
14165245Smsmithstatic int	amr_quartz_submit_command(struct amr_softc *sc);
14265245Smsmithstatic int	amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
143107756Semoorestatic int	amr_quartz_poll_command(struct amr_command *ac);
14451974Smsmith
14565245Smsmithstatic int	amr_std_submit_command(struct amr_softc *sc);
14665245Smsmithstatic int	amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
147107756Semoorestatic int	amr_std_poll_command(struct amr_command *ac);
14865245Smsmithstatic void	amr_std_attach_mailbox(struct amr_softc *sc);
14951974Smsmith
15065245Smsmith#ifdef AMR_BOARD_INIT
15165245Smsmithstatic int	amr_quartz_init(struct amr_softc *sc);
15265245Smsmithstatic int	amr_std_init(struct amr_softc *sc);
15365245Smsmith#endif
15465245Smsmith
15551974Smsmith/*
15651974Smsmith * Debugging
15751974Smsmith */
15865245Smsmithstatic void	amr_describe_controller(struct amr_softc *sc);
15965245Smsmith#ifdef AMR_DEBUG
160107756Semoore#if 0
16165245Smsmithstatic void	amr_printcommand(struct amr_command *ac);
16265245Smsmith#endif
163107756Semoore#endif
16451974Smsmith
16551974Smsmith/********************************************************************************
16651974Smsmith ********************************************************************************
16765245Smsmith                                                                      Inline Glue
16851974Smsmith ********************************************************************************
16951974Smsmith ********************************************************************************/
17051974Smsmith
17151974Smsmith/********************************************************************************
17265245Smsmith ********************************************************************************
17365245Smsmith                                                                Public Interfaces
17465245Smsmith ********************************************************************************
17565245Smsmith ********************************************************************************/
17651974Smsmith
17751974Smsmith/********************************************************************************
17851974Smsmith * Initialise the controller and softc.
17951974Smsmith */
18051974Smsmithint
18151974Smsmithamr_attach(struct amr_softc *sc)
18251974Smsmith{
18351974Smsmith
18465245Smsmith    debug_called(1);
18565245Smsmith
18651974Smsmith    /*
18751974Smsmith     * Initialise per-controller queues.
18851974Smsmith     */
18965245Smsmith    TAILQ_INIT(&sc->amr_completed);
19051974Smsmith    TAILQ_INIT(&sc->amr_freecmds);
19165245Smsmith    TAILQ_INIT(&sc->amr_cmd_clusters);
19265245Smsmith    TAILQ_INIT(&sc->amr_ready);
19359249Sphk    bioq_init(&sc->amr_bioq);
19451974Smsmith
19565245Smsmith#if __FreeBSD_version >= 500005
19651974Smsmith    /*
19765245Smsmith     * Initialise command-completion task.
19865245Smsmith     */
19965245Smsmith    TASK_INIT(&sc->amr_task_complete, 0, amr_complete, sc);
20065245Smsmith#endif
20165245Smsmith
20265245Smsmith    debug(2, "queue init done");
20365245Smsmith
20465245Smsmith    /*
20551974Smsmith     * Configure for this controller type.
20651974Smsmith     */
20765245Smsmith    if (AMR_IS_QUARTZ(sc)) {
20851974Smsmith	sc->amr_submit_command = amr_quartz_submit_command;
20951974Smsmith	sc->amr_get_work       = amr_quartz_get_work;
210107756Semoore	sc->amr_poll_command   = amr_quartz_poll_command;
21151974Smsmith    } else {
21251974Smsmith	sc->amr_submit_command = amr_std_submit_command;
21351974Smsmith	sc->amr_get_work       = amr_std_get_work;
214107756Semoore	sc->amr_poll_command   = amr_std_poll_command;
21565245Smsmith	amr_std_attach_mailbox(sc);;
21651974Smsmith    }
21751974Smsmith
21865245Smsmith#ifdef AMR_BOARD_INIT
21965245Smsmith    if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc))))
22065245Smsmith	return(ENXIO);
22165245Smsmith#endif
22251974Smsmith
22351974Smsmith    /*
22465245Smsmith     * Quiz controller for features and limits.
22551974Smsmith     */
22665245Smsmith    if (amr_query_controller(sc))
22765245Smsmith	return(ENXIO);
22851974Smsmith
22965245Smsmith    debug(2, "controller query complete");
23051974Smsmith
23151974Smsmith    /*
23265245Smsmith     * Attach our 'real' SCSI channels to CAM.
23351974Smsmith     */
23465245Smsmith    if (amr_cam_attach(sc))
23551974Smsmith	return(ENXIO);
23665245Smsmith    debug(2, "CAM attach done");
23751974Smsmith
23851974Smsmith    /*
23965245Smsmith     * Create the control device.
24051974Smsmith     */
24165245Smsmith    sc->amr_dev_t = make_dev(&amr_cdevsw, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR,
24265245Smsmith			     S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev));
24365245Smsmith    sc->amr_dev_t->si_drv1 = sc;
24451974Smsmith
24551974Smsmith    /*
24665245Smsmith     * Schedule ourselves to bring the controller up once interrupts are
24765245Smsmith     * available.
24851974Smsmith     */
24965245Smsmith    bzero(&sc->amr_ich, sizeof(struct intr_config_hook));
25065245Smsmith    sc->amr_ich.ich_func = amr_startup;
25165245Smsmith    sc->amr_ich.ich_arg = sc;
25265245Smsmith    if (config_intrhook_establish(&sc->amr_ich) != 0) {
25365245Smsmith	device_printf(sc->amr_dev, "can't establish configuration hook\n");
25465245Smsmith	return(ENOMEM);
25565245Smsmith    }
25651974Smsmith
25758883Smsmith    /*
25865245Smsmith     * Print a little information about the controller.
25958883Smsmith     */
26065245Smsmith    amr_describe_controller(sc);
26158883Smsmith
26265245Smsmith    debug(2, "attach complete");
26351974Smsmith    return(0);
26451974Smsmith}
26551974Smsmith
26651974Smsmith/********************************************************************************
26751974Smsmith * Locate disk resources and attach children to them.
26851974Smsmith */
26965245Smsmithstatic void
27065245Smsmithamr_startup(void *arg)
27151974Smsmith{
27265245Smsmith    struct amr_softc	*sc = (struct amr_softc *)arg;
27351974Smsmith    struct amr_logdrive	*dr;
27451974Smsmith    int			i, error;
27551974Smsmith
27665245Smsmith    debug_called(1);
27751974Smsmith
27865245Smsmith    /* pull ourselves off the intrhook chain */
27965245Smsmith    config_intrhook_disestablish(&sc->amr_ich);
28065245Smsmith
28151974Smsmith    /* get up-to-date drive information */
28251974Smsmith    if (amr_query_controller(sc)) {
28365245Smsmith	device_printf(sc->amr_dev, "can't scan controller for drives\n");
28451974Smsmith	return;
28551974Smsmith    }
28651974Smsmith
28751974Smsmith    /* iterate over available drives */
28851974Smsmith    for (i = 0, dr = &sc->amr_drive[0]; (i < AMR_MAXLD) && (dr->al_size != 0xffffffff); i++, dr++) {
28951974Smsmith	/* are we already attached to this drive? */
29051974Smsmith	if (dr->al_disk == 0) {
29151974Smsmith	    /* generate geometry information */
29251974Smsmith	    if (dr->al_size > 0x200000) {	/* extended translation? */
29351974Smsmith		dr->al_heads = 255;
29451974Smsmith		dr->al_sectors = 63;
29551974Smsmith	    } else {
29651974Smsmith		dr->al_heads = 64;
29751974Smsmith		dr->al_sectors = 32;
29851974Smsmith	    }
29951974Smsmith	    dr->al_cylinders = dr->al_size / (dr->al_heads * dr->al_sectors);
30051974Smsmith
30154073Smdodd	    dr->al_disk = device_add_child(sc->amr_dev, NULL, -1);
30251974Smsmith	    if (dr->al_disk == 0)
30351974Smsmith		device_printf(sc->amr_dev, "device_add_child failed\n");
30454073Smdodd	    device_set_ivars(dr->al_disk, dr);
30551974Smsmith	}
30651974Smsmith    }
30751974Smsmith
30851974Smsmith    if ((error = bus_generic_attach(sc->amr_dev)) != 0)
30951974Smsmith	device_printf(sc->amr_dev, "bus_generic_attach returned %d\n", error);
31051974Smsmith
31151974Smsmith    /* mark controller back up */
31251974Smsmith    sc->amr_state &= ~AMR_STATE_SHUTDOWN;
31351974Smsmith
31451974Smsmith    /* interrupts will be enabled before we do anything more */
31551974Smsmith    sc->amr_state |= AMR_STATE_INTEN;
31651974Smsmith
31751974Smsmith    /*
31865245Smsmith     * Start the timeout routine.
31951974Smsmith     */
32065245Smsmith/*    sc->amr_timeout = timeout(amr_periodic, sc, hz);*/
32151974Smsmith
32265245Smsmith    return;
32351974Smsmith}
32451974Smsmith
32565245Smsmith/*******************************************************************************
32665245Smsmith * Free resources associated with a controller instance
32751974Smsmith */
32865245Smsmithvoid
32965245Smsmithamr_free(struct amr_softc *sc)
33051974Smsmith{
33165245Smsmith    struct amr_command_cluster	*acc;
33251974Smsmith
33365245Smsmith    /* detach from CAM */
334107756Semoore    amr_cam_detach(sc);
33551974Smsmith
33665245Smsmith    /* cancel status timeout */
33765245Smsmith    untimeout(amr_periodic, sc, sc->amr_timeout);
33851974Smsmith
33965245Smsmith    /* throw away any command buffers */
34065245Smsmith    while ((acc = TAILQ_FIRST(&sc->amr_cmd_clusters)) != NULL) {
34165245Smsmith	TAILQ_REMOVE(&sc->amr_cmd_clusters, acc, acc_link);
34265245Smsmith	amr_freecmd_cluster(acc);
34351974Smsmith    }
344107756Semoore
345107756Semoore    /* destroy control device */
346130585Sphk    if( sc->amr_dev_t != (struct cdev *)NULL)
347107756Semoore	    destroy_dev(sc->amr_dev_t);
34851974Smsmith}
34951974Smsmith
35051974Smsmith/*******************************************************************************
35165245Smsmith * Receive a bio structure from a child device and queue it on a particular
35251974Smsmith * disk resource, then poke the disk resource to start as much work as it can.
35351974Smsmith */
35451974Smsmithint
35565245Smsmithamr_submit_bio(struct amr_softc *sc, struct bio *bio)
35651974Smsmith{
35765245Smsmith    debug_called(2);
35852543Smsmith
35965245Smsmith    amr_enqueue_bio(sc, bio);
36051974Smsmith    amr_startio(sc);
36151974Smsmith    return(0);
36251974Smsmith}
36351974Smsmith
36451974Smsmith/********************************************************************************
36551974Smsmith * Accept an open operation on the control device.
36651974Smsmith */
367104094Sphkstatic int
368130585Sphkamr_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
36951974Smsmith{
37051974Smsmith    int			unit = minor(dev);
37189055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
37251974Smsmith
37365245Smsmith    debug_called(1);
37465245Smsmith
37551974Smsmith    sc->amr_state |= AMR_STATE_OPEN;
37651974Smsmith    return(0);
37751974Smsmith}
37851974Smsmith
37951974Smsmith/********************************************************************************
38051974Smsmith * Accept the last close on the control device.
38151974Smsmith */
382104094Sphkstatic int
383130585Sphkamr_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
38451974Smsmith{
38551974Smsmith    int			unit = minor(dev);
38689055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
38751974Smsmith
38865245Smsmith    debug_called(1);
38965245Smsmith
39051974Smsmith    sc->amr_state &= ~AMR_STATE_OPEN;
39151974Smsmith    return (0);
39251974Smsmith}
39351974Smsmith
39451974Smsmith/********************************************************************************
39551974Smsmith * Handle controller-specific control operations.
39651974Smsmith */
397104094Sphkstatic int
398130585Sphkamr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
39951974Smsmith{
40065245Smsmith    struct amr_softc		*sc = (struct amr_softc *)dev->si_drv1;
401133870Sambrisko    union {
402133870Sambrisko	void			*_p;
403133870Sambrisko	struct amr_user_ioctl	*au;
404133870Sambrisko#ifdef AMR_IO_COMMAND32
405133870Sambrisko	struct amr_user_ioctl32	*au32;
406133870Sambrisko#endif
407133870Sambrisko	int			*result;
408133870Sambrisko    } arg;
40965245Smsmith    struct amr_command		*ac;
41065245Smsmith    struct amr_mailbox_ioctl	*mbi;
41165245Smsmith    struct amr_passthrough	*ap;
412133870Sambrisko    void			*dp, *au_buffer;
413133870Sambrisko    unsigned long		au_length;
414133870Sambrisko    unsigned char		*au_cmd;
415133870Sambrisko    int				*au_statusp, au_direction;
41665245Smsmith    int				error;
41765245Smsmith
41865245Smsmith    debug_called(1);
41965245Smsmith
420133870Sambrisko    arg._p = (void *)addr;
421133870Sambrisko
42251974Smsmith    switch(cmd) {
42365245Smsmith
42465245Smsmith    case AMR_IO_VERSION:
42565245Smsmith	debug(1, "AMR_IO_VERSION");
426133870Sambrisko	*arg.result = AMR_IO_VERSION_NUMBER;
427133870Sambrisko	return(0);
428133870Sambrisko
429133870Sambrisko#ifdef AMR_IO_COMMAND32
430133870Sambrisko    /*
431133870Sambrisko     * Accept ioctl-s from 32-bit binaries on non-32-bit
432133870Sambrisko     * platforms, such as AMD. LSI's MEGAMGR utility is
433133870Sambrisko     * the only example known today...	-mi
434133870Sambrisko     */
435133870Sambrisko    case AMR_IO_COMMAND32:
436133870Sambrisko	debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]);
437133870Sambrisko	au_cmd = arg.au32->au_cmd;
438133870Sambrisko	au_buffer = (void *)(u_int64_t)arg.au32->au_buffer;
439133870Sambrisko	au_length = arg.au32->au_length;
440133870Sambrisko	au_direction = arg.au32->au_direction;
441133870Sambrisko	au_statusp = &arg.au32->au_status;
44265245Smsmith	break;
443133870Sambrisko#endif
44465245Smsmith
44565245Smsmith    case AMR_IO_COMMAND:
446133870Sambrisko	debug(1, "AMR_IO_COMMAND  0x%x", arg.au->au_cmd[0]);
447133870Sambrisko	au_cmd = arg.au->au_cmd;
448133870Sambrisko	au_buffer = (void *)arg.au->au_buffer;
449133870Sambrisko	au_length = arg.au->au_length;
450133870Sambrisko	au_direction = arg.au->au_direction;
451133870Sambrisko	au_statusp = &arg.au->au_status;
452133870Sambrisko	break;
45365245Smsmith
454133870Sambrisko    default:
455133870Sambrisko	debug(1, "unknown ioctl 0x%lx", cmd);
456133870Sambrisko	return(ENOIOCTL);
457133870Sambrisko    }
45865245Smsmith
459133870Sambrisko    error = 0;
460133870Sambrisko    dp = NULL;
461133870Sambrisko    ap = NULL;
462133870Sambrisko    ac = NULL;
46365245Smsmith
464133870Sambrisko    /* handle inbound data buffer */
465133870Sambrisko    if (au_length != 0) {
466133870Sambrisko	if ((dp = malloc(au_length, M_DEVBUF, M_WAITOK)) == NULL)
467133870Sambrisko	    return(ENOMEM);
46865245Smsmith
469133870Sambrisko	if ((error = copyin(au_buffer, dp, au_length)) != 0)
470133870Sambrisko	    goto out;
471133870Sambrisko	debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp);
472133870Sambrisko    }
47365245Smsmith
474133870Sambrisko    if ((ac = amr_alloccmd(sc)) == NULL) {
475133870Sambrisko	error = ENOMEM;
476133870Sambrisko	goto out;
477133870Sambrisko    }
47865245Smsmith
479133870Sambrisko    /* handle SCSI passthrough command */
480133870Sambrisko    if (au_cmd[0] == AMR_CMD_PASS) {
481133870Sambrisko	if ((ap = malloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
482133870Sambrisko	    error = ENOMEM;
483133870Sambrisko	    goto out;
484133870Sambrisko	}
48565245Smsmith
486133870Sambrisko	/* copy cdb */
487133870Sambrisko	ap->ap_cdb_length = au_cmd[2];
488133870Sambrisko	bcopy(au_cmd + 3, ap->ap_cdb, ap->ap_cdb_length);
48965245Smsmith
490133870Sambrisko	/* build passthrough */
491133870Sambrisko	ap->ap_timeout		= au_cmd[ap->ap_cdb_length + 3] & 0x07;
492133870Sambrisko	ap->ap_ars		= (au_cmd[ap->ap_cdb_length + 3] & 0x08) ? 1 : 0;
493133870Sambrisko	ap->ap_islogical	= (au_cmd[ap->ap_cdb_length + 3] & 0x80) ? 1 : 0;
494133870Sambrisko	ap->ap_logical_drive_no	= au_cmd[ap->ap_cdb_length + 4];
495133870Sambrisko	ap->ap_channel		= au_cmd[ap->ap_cdb_length + 5];
496133870Sambrisko	ap->ap_scsi_id 		= au_cmd[ap->ap_cdb_length + 6];
497133870Sambrisko	ap->ap_request_sense_length	= 14;
498133870Sambrisko	ap->ap_data_transfer_length	= au_length;
499133870Sambrisko	/* XXX what about the request-sense area? does the caller want it? */
50065245Smsmith
501133870Sambrisko	/* build command */
502133870Sambrisko	ac->ac_data = ap;
503133870Sambrisko	ac->ac_length = sizeof(*ap);
504133870Sambrisko	ac->ac_flags |= AMR_CMD_DATAOUT;
505133870Sambrisko	ac->ac_ccb_data = dp;
506133870Sambrisko	ac->ac_ccb_length = au_length;
507133870Sambrisko	if (au_direction & AMR_IO_READ)
508133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAIN;
509133870Sambrisko	if (au_direction & AMR_IO_WRITE)
510133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
51165245Smsmith
512133870Sambrisko	ac->ac_mailbox.mb_command = AMR_CMD_PASS;
51365245Smsmith
514133870Sambrisko    } else {
515133870Sambrisko	/* direct command to controller */
516133870Sambrisko	mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
517105419Semoore
518133870Sambrisko	/* copy pertinent mailbox items */
519133870Sambrisko	mbi->mb_command = au_cmd[0];
520133870Sambrisko	mbi->mb_channel = au_cmd[1];
521133870Sambrisko	mbi->mb_param = au_cmd[2];
522133870Sambrisko	mbi->mb_pad[0] = au_cmd[3];
523133870Sambrisko	mbi->mb_drive = au_cmd[4];
524133870Sambrisko
525133870Sambrisko	/* build the command */
526133870Sambrisko	ac->ac_data = dp;
527133870Sambrisko	ac->ac_length = au_length;
528133870Sambrisko	if (au_direction & AMR_IO_READ)
529133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAIN;
530133870Sambrisko	if (au_direction & AMR_IO_WRITE)
531133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAOUT;
53251974Smsmith    }
53351974Smsmith
534133870Sambrisko    /* run the command */
535133870Sambrisko    if ((error = amr_wait_command(ac)) != 0)
536133870Sambrisko	goto out;
537133870Sambrisko
538133870Sambrisko    /* copy out data and set status */
539133870Sambrisko    if (au_length != 0)
540133870Sambrisko	error = copyout(dp, au_buffer, au_length);
541133870Sambrisko    debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
54265245Smsmith    if (dp != NULL)
543133870Sambrisko	debug(2, "%16d", (int)dp);
544133870Sambrisko    *au_statusp = ac->ac_status;
545133870Sambrisko
546133870Sambriskoout:
547133870Sambrisko    if (dp != NULL)
54865245Smsmith	free(dp, M_DEVBUF);
54965245Smsmith    if (ap != NULL)
55065245Smsmith	free(ap, M_DEVBUF);
55165245Smsmith    if (ac != NULL)
55265245Smsmith	amr_releasecmd(ac);
55365245Smsmith    return(error);
55451974Smsmith}
55551974Smsmith
55651974Smsmith/********************************************************************************
55751974Smsmith ********************************************************************************
55858883Smsmith                                                                Status Monitoring
55958883Smsmith ********************************************************************************
56058883Smsmith ********************************************************************************/
56158883Smsmith
56258883Smsmith/********************************************************************************
56358883Smsmith * Perform a periodic check of the controller status
56458883Smsmith */
56558883Smsmithstatic void
56658883Smsmithamr_periodic(void *data)
56758883Smsmith{
56858883Smsmith    struct amr_softc	*sc = (struct amr_softc *)data;
56958883Smsmith
57065245Smsmith    debug_called(2);
57158883Smsmith
57265245Smsmith    /* XXX perform periodic status checks here */
57358883Smsmith
57465245Smsmith    /* compensate for missed interrupts */
57565245Smsmith    amr_done(sc);
57665245Smsmith
57758883Smsmith    /* reschedule */
57858883Smsmith    sc->amr_timeout = timeout(amr_periodic, sc, hz);
57958883Smsmith}
58058883Smsmith
58158883Smsmith/********************************************************************************
58258883Smsmith ********************************************************************************
58351974Smsmith                                                                 Command Wrappers
58451974Smsmith ********************************************************************************
58551974Smsmith ********************************************************************************/
58651974Smsmith
58751974Smsmith/********************************************************************************
58851974Smsmith * Interrogate the controller for the operational parameters we require.
58951974Smsmith */
59051974Smsmithstatic int
59151974Smsmithamr_query_controller(struct amr_softc *sc)
59251974Smsmith{
59365245Smsmith    struct amr_enquiry3	*aex;
59465245Smsmith    struct amr_prodinfo	*ap;
59565245Smsmith    struct amr_enquiry	*ae;
59665245Smsmith    int			ldrv;
59751974Smsmith
59865245Smsmith    /*
59965245Smsmith     * If we haven't found the real limit yet, let us have a couple of commands in
60065245Smsmith     * order to be able to probe.
60165245Smsmith     */
60265245Smsmith    if (sc->amr_maxio == 0)
60365245Smsmith	sc->amr_maxio = 2;
60451974Smsmith
605106225Semoore    /*
606106225Semoore     * Greater than 10 byte cdb support
607106225Semoore     */
608106225Semoore    sc->support_ext_cdb = amr_support_ext_cdb(sc);
609106225Semoore
610106225Semoore    if(sc->support_ext_cdb) {
611106225Semoore	debug(2,"supports extended CDBs.");
612106225Semoore    }
613106225Semoore
61465245Smsmith    /*
61565245Smsmith     * Try to issue an ENQUIRY3 command
61665245Smsmith     */
61765245Smsmith    if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
61865245Smsmith			   AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
61951974Smsmith
62065245Smsmith	/*
62165245Smsmith	 * Fetch current state of logical drives.
62265245Smsmith	 */
62365245Smsmith	for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
62465245Smsmith	    sc->amr_drive[ldrv].al_size       = aex->ae_drivesize[ldrv];
62565245Smsmith	    sc->amr_drive[ldrv].al_state      = aex->ae_drivestate[ldrv];
62665245Smsmith	    sc->amr_drive[ldrv].al_properties = aex->ae_driveprop[ldrv];
62765245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
62865245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
62951974Smsmith	}
63065245Smsmith	free(aex, M_DEVBUF);
63158883Smsmith
63265245Smsmith	/*
63365245Smsmith	 * Get product info for channel count.
63458883Smsmith	 */
63565245Smsmith	if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
63665245Smsmith	    device_printf(sc->amr_dev, "can't obtain product data from controller\n");
63765245Smsmith	    return(1);
63865245Smsmith	}
63965245Smsmith	sc->amr_maxdrives = 40;
64065245Smsmith	sc->amr_maxchan = ap->ap_nschan;
64165245Smsmith	sc->amr_maxio = ap->ap_maxio;
64265245Smsmith	sc->amr_type |= AMR_TYPE_40LD;
64365245Smsmith	free(ap, M_DEVBUF);
64458883Smsmith
64565245Smsmith    } else {
64665245Smsmith
64765245Smsmith	/* failed, try the 8LD ENQUIRY commands */
64865245Smsmith	if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) {
64965245Smsmith	    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) {
65065245Smsmith		device_printf(sc->amr_dev, "can't obtain configuration data from controller\n");
65165245Smsmith		return(1);
65265245Smsmith	    }
65365245Smsmith	    ae->ae_signature = 0;
65451974Smsmith	}
65565245Smsmith
65658883Smsmith	/*
65765245Smsmith	 * Fetch current state of logical drives.
65858883Smsmith	 */
65965245Smsmith	for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
66065245Smsmith	    sc->amr_drive[ldrv].al_size       = ae->ae_ldrv.al_size[ldrv];
66165245Smsmith	    sc->amr_drive[ldrv].al_state      = ae->ae_ldrv.al_state[ldrv];
66265245Smsmith	    sc->amr_drive[ldrv].al_properties = ae->ae_ldrv.al_properties[ldrv];
66365245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
66465245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
66551974Smsmith	}
66665245Smsmith
66765245Smsmith	sc->amr_maxdrives = 8;
66865245Smsmith	sc->amr_maxchan = ae->ae_adapter.aa_channels;
66965245Smsmith	sc->amr_maxio = ae->ae_adapter.aa_maxio;
67065245Smsmith	free(ae, M_DEVBUF);
67151974Smsmith    }
67265245Smsmith
67365245Smsmith    /*
67465245Smsmith     * Mark remaining drives as unused.
67565245Smsmith     */
67665245Smsmith    for (; ldrv < AMR_MAXLD; ldrv++)
67765245Smsmith	sc->amr_drive[ldrv].al_size = 0xffffffff;
67865245Smsmith
67965245Smsmith    /*
68065245Smsmith     * Cap the maximum number of outstanding I/Os.  AMI's Linux driver doesn't trust
68165245Smsmith     * the controller's reported value, and lockups have been seen when we do.
68265245Smsmith     */
68365245Smsmith    sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD);
68465245Smsmith
68551974Smsmith    return(0);
68651974Smsmith}
68751974Smsmith
68851974Smsmith/********************************************************************************
68951974Smsmith * Run a generic enquiry-style command.
69051974Smsmith */
69151974Smsmithstatic void *
69251974Smsmithamr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
69351974Smsmith{
69451974Smsmith    struct amr_command	*ac;
69551974Smsmith    void		*result;
69651974Smsmith    u_int8_t		*mbox;
69751974Smsmith    int			error;
69851974Smsmith
69965245Smsmith    debug_called(1);
70051974Smsmith
70151974Smsmith    error = 1;
70251974Smsmith    result = NULL;
70351974Smsmith
70451974Smsmith    /* get ourselves a command buffer */
70551974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
70651974Smsmith	goto out;
70751974Smsmith    /* allocate the response structure */
70851974Smsmith    if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL)
70951974Smsmith	goto out;
71065245Smsmith    /* set command flags */
71151974Smsmith    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
71251974Smsmith
71365245Smsmith    /* point the command at our data */
71451974Smsmith    ac->ac_data = result;
71551974Smsmith    ac->ac_length = bufsize;
71651974Smsmith
71751974Smsmith    /* build the command proper */
71851974Smsmith    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
71951974Smsmith    mbox[0] = cmd;
72051974Smsmith    mbox[2] = cmdsub;
72151974Smsmith    mbox[3] = cmdqual;
72251974Smsmith
72358883Smsmith    /* can't assume that interrupts are going to work here, so play it safe */
724107756Semoore    if (sc->amr_poll_command(ac))
72551974Smsmith	goto out;
72651974Smsmith    error = ac->ac_status;
72751974Smsmith
72851974Smsmith out:
72951974Smsmith    if (ac != NULL)
73051974Smsmith	amr_releasecmd(ac);
73151974Smsmith    if ((error != 0) && (result != NULL)) {
73251974Smsmith	free(result, M_DEVBUF);
73351974Smsmith	result = NULL;
73451974Smsmith    }
73551974Smsmith    return(result);
73651974Smsmith}
73751974Smsmith
73851974Smsmith/********************************************************************************
73951974Smsmith * Flush the controller's internal cache, return status.
74051974Smsmith */
74165245Smsmithint
74251974Smsmithamr_flush(struct amr_softc *sc)
74351974Smsmith{
74451974Smsmith    struct amr_command	*ac;
74551974Smsmith    int			error;
74651974Smsmith
74751974Smsmith    /* get ourselves a command buffer */
74851974Smsmith    error = 1;
74951974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
75051974Smsmith	goto out;
75165245Smsmith    /* set command flags */
75251974Smsmith    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
75351974Smsmith
75451974Smsmith    /* build the command proper */
75551974Smsmith    ac->ac_mailbox.mb_command = AMR_CMD_FLUSH;
75651974Smsmith
75758883Smsmith    /* we have to poll, as the system may be going down or otherwise damaged */
758107756Semoore    if (sc->amr_poll_command(ac))
75951974Smsmith	goto out;
76051974Smsmith    error = ac->ac_status;
76151974Smsmith
76251974Smsmith out:
76351974Smsmith    if (ac != NULL)
76451974Smsmith	amr_releasecmd(ac);
76551974Smsmith    return(error);
76651974Smsmith}
76751974Smsmith
76851974Smsmith/********************************************************************************
769106225Semoore * Detect extented cdb >> greater than 10 byte cdb support
770106225Semoore * returns '1' means this support exist
771106225Semoore * returns '0' means this support doesn't exist
772106225Semoore */
773106225Semoorestatic int
774106225Semooreamr_support_ext_cdb(struct amr_softc *sc)
775106225Semoore{
776106225Semoore    struct amr_command	*ac;
777106225Semoore    u_int8_t		*mbox;
778106225Semoore    int			error;
779106225Semoore
780106225Semoore    /* get ourselves a command buffer */
781106225Semoore    error = 0;
782106225Semoore    if ((ac = amr_alloccmd(sc)) == NULL)
783106225Semoore	goto out;
784106225Semoore    /* set command flags */
785106225Semoore    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
786106225Semoore
787106225Semoore    /* build the command proper */
788106225Semoore    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
789106225Semoore    mbox[0] = 0xA4;
790106225Semoore    mbox[2] = 0x16;
791106225Semoore
792106225Semoore
793106225Semoore    /* we have to poll, as the system may be going down or otherwise damaged */
794107756Semoore    if (sc->amr_poll_command(ac))
795106225Semoore	goto out;
796106225Semoore    if( ac->ac_status == AMR_STATUS_SUCCESS ) {
797106225Semoore	    error = 1;
798106225Semoore    }
799106225Semoore
800106225Semooreout:
801106225Semoore    if (ac != NULL)
802106225Semoore	amr_releasecmd(ac);
803106225Semoore    return(error);
804106225Semoore}
805106225Semoore
806106225Semoore/********************************************************************************
80765245Smsmith * Try to find I/O work for the controller from one or more of the work queues.
80851974Smsmith *
80965245Smsmith * We make the assumption that if the controller is not ready to take a command
81065245Smsmith * at some given time, it will generate an interrupt at some later time when
81165245Smsmith * it is.
81251974Smsmith */
81365245Smsmithvoid
81451974Smsmithamr_startio(struct amr_softc *sc)
81551974Smsmith{
81651974Smsmith    struct amr_command	*ac;
81751974Smsmith
81851974Smsmith    /* spin until something prevents us from doing any work */
81951974Smsmith    for (;;) {
82051974Smsmith
82165245Smsmith	/* try to get a ready command */
82265245Smsmith	ac = amr_dequeue_ready(sc);
82351974Smsmith
82465245Smsmith	/* if that failed, build a command from a bio */
82565245Smsmith	if (ac == NULL)
82665245Smsmith	    (void)amr_bio_command(sc, &ac);
82751974Smsmith
82865245Smsmith	/* if that failed, build a command from a ccb */
82965245Smsmith	if (ac == NULL)
83065245Smsmith	    (void)amr_cam_command(sc, &ac);
831105419Semoore
83265245Smsmith	/* if we don't have anything to do, give up */
83365245Smsmith	if (ac == NULL)
83465245Smsmith	    break;
83551974Smsmith
83665245Smsmith	/* try to give the command to the controller; if this fails save it for later and give up */
83765245Smsmith	if (amr_start(ac)) {
83865245Smsmith	    debug(2, "controller busy, command deferred");
83965245Smsmith	    amr_requeue_ready(ac);	/* XXX schedule retry very soon? */
84065245Smsmith	    break;
84151974Smsmith	}
84251974Smsmith    }
84351974Smsmith}
84451974Smsmith
84551974Smsmith/********************************************************************************
84651974Smsmith * Handle completion of an I/O command.
84751974Smsmith */
84851974Smsmithstatic void
84951974Smsmithamr_completeio(struct amr_command *ac)
85051974Smsmith{
85151974Smsmith    struct amr_softc	*sc = ac->ac_sc;
85251974Smsmith
85351974Smsmith    if (ac->ac_status != AMR_STATUS_SUCCESS) {	/* could be more verbose here? */
85465245Smsmith	ac->ac_bio->bio_error = EIO;
85565245Smsmith	ac->ac_bio->bio_flags |= BIO_ERROR;
85651974Smsmith
85765245Smsmith	device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status);
85865245Smsmith/*	amr_printcommand(ac);*/
85951974Smsmith    }
86065245Smsmith    amrd_intr(ac->ac_bio);
86165245Smsmith    amr_releasecmd(ac);
86251974Smsmith}
86351974Smsmith
86451974Smsmith/********************************************************************************
86551974Smsmith ********************************************************************************
86651974Smsmith                                                               Command Processing
86751974Smsmith ********************************************************************************
86851974Smsmith ********************************************************************************/
86951974Smsmith
87051974Smsmith/********************************************************************************
87165245Smsmith * Convert a bio off the top of the bio queue into a command.
87265245Smsmith */
87365245Smsmithstatic int
87465245Smsmithamr_bio_command(struct amr_softc *sc, struct amr_command **acp)
87565245Smsmith{
87665245Smsmith    struct amr_command	*ac;
87765245Smsmith    struct amrd_softc	*amrd;
87865245Smsmith    struct bio		*bio;
87965245Smsmith    int			error;
88065245Smsmith    int			blkcount;
88165245Smsmith    int			driveno;
88265245Smsmith    int			cmd;
88365245Smsmith
88465245Smsmith    ac = NULL;
88565245Smsmith    error = 0;
88665245Smsmith
88765245Smsmith    /* get a bio to work on */
88865245Smsmith    if ((bio = amr_dequeue_bio(sc)) == NULL)
88965245Smsmith	goto out;
89065245Smsmith
89165245Smsmith    /* get a command */
89265245Smsmith    if ((ac = amr_alloccmd(sc)) == NULL) {
89365245Smsmith	error = ENOMEM;
89465245Smsmith	goto out;
89565245Smsmith    }
89665245Smsmith
89765245Smsmith    /* connect the bio to the command */
89865245Smsmith    ac->ac_complete = amr_completeio;
89965245Smsmith    ac->ac_bio = bio;
90065245Smsmith    ac->ac_data = bio->bio_data;
90165245Smsmith    ac->ac_length = bio->bio_bcount;
90265245Smsmith    if (BIO_IS_READ(bio)) {
90365245Smsmith	ac->ac_flags |= AMR_CMD_DATAIN;
90465245Smsmith	cmd = AMR_CMD_LREAD;
90565245Smsmith    } else {
90665245Smsmith	ac->ac_flags |= AMR_CMD_DATAOUT;
90765245Smsmith	cmd = AMR_CMD_LWRITE;
90865245Smsmith    }
909111441Sphk    amrd = (struct amrd_softc *)bio->bio_disk->d_drv1;
91065245Smsmith    driveno = amrd->amrd_drive - sc->amr_drive;
91165245Smsmith    blkcount = (bio->bio_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE;
91265245Smsmith
91365245Smsmith    ac->ac_mailbox.mb_command = cmd;
91465245Smsmith    ac->ac_mailbox.mb_blkcount = blkcount;
91565245Smsmith    ac->ac_mailbox.mb_lba = bio->bio_pblkno;
91665245Smsmith    ac->ac_mailbox.mb_drive = driveno;
91765245Smsmith    /* we fill in the s/g related data when the command is mapped */
91865245Smsmith
91965245Smsmith    if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size)
92092610Sbde	device_printf(sc->amr_dev, "I/O beyond end of unit (%lld,%d > %lu)\n",
92192610Sbde		      (long long)bio->bio_pblkno, blkcount,
92292610Sbde		      (u_long)sc->amr_drive[driveno].al_size);
92365245Smsmith
92465245Smsmithout:
92565245Smsmith    if (error != 0) {
92665245Smsmith	if (ac != NULL)
92765245Smsmith	    amr_releasecmd(ac);
92865245Smsmith	if (bio != NULL)			/* this breaks ordering... */
92965245Smsmith	    amr_enqueue_bio(sc, bio);
93065245Smsmith    }
93165245Smsmith    *acp = ac;
93265245Smsmith    return(error);
93365245Smsmith}
93465245Smsmith
93565245Smsmith/********************************************************************************
93651974Smsmith * Take a command, submit it to the controller and sleep until it completes
93751974Smsmith * or fails.  Interrupts must be enabled, returns nonzero on error.
93851974Smsmith */
93951974Smsmithstatic int
94051974Smsmithamr_wait_command(struct amr_command *ac)
94151974Smsmith{
94251974Smsmith    int			error, count;
94351974Smsmith
94465245Smsmith    debug_called(1);
94551974Smsmith
94651974Smsmith    ac->ac_complete = NULL;
94765245Smsmith    ac->ac_flags |= AMR_CMD_SLEEP;
94851974Smsmith    if ((error = amr_start(ac)) != 0)
94951974Smsmith	return(error);
95051974Smsmith
95151974Smsmith    count = 0;
95251974Smsmith    /* XXX better timeout? */
95365245Smsmith    while ((ac->ac_flags & AMR_CMD_BUSY) && (count < 30)) {
95465245Smsmith	tsleep(ac, PRIBIO | PCATCH, "amrwcmd", hz);
95551974Smsmith    }
95651974Smsmith    return(0);
95751974Smsmith}
95851974Smsmith
95951974Smsmith/********************************************************************************
96051974Smsmith * Take a command, submit it to the controller and busy-wait for it to return.
96151974Smsmith * Returns nonzero on error.  Can be safely called with interrupts enabled.
96251974Smsmith */
96351974Smsmithstatic int
964107756Semooreamr_std_poll_command(struct amr_command *ac)
96551974Smsmith{
96651974Smsmith    struct amr_softc	*sc = ac->ac_sc;
96765245Smsmith    int			error, count;
96851974Smsmith
96965245Smsmith    debug_called(2);
97051974Smsmith
97151974Smsmith    ac->ac_complete = NULL;
97251974Smsmith    if ((error = amr_start(ac)) != 0)
97351974Smsmith	return(error);
97451974Smsmith
97551974Smsmith    count = 0;
97651974Smsmith    do {
97751974Smsmith	/*
97851974Smsmith	 * Poll for completion, although the interrupt handler may beat us to it.
97951974Smsmith	 * Note that the timeout here is somewhat arbitrary.
98051974Smsmith	 */
98151974Smsmith	amr_done(sc);
98265245Smsmith	DELAY(1000);
98365245Smsmith    } while ((ac->ac_flags & AMR_CMD_BUSY) && (count++ < 1000));
98465245Smsmith    if (!(ac->ac_flags & AMR_CMD_BUSY)) {
98551974Smsmith	error = 0;
98651974Smsmith    } else {
98765245Smsmith	/* XXX the slot is now marked permanently busy */
98851974Smsmith	error = EIO;
98965245Smsmith	device_printf(sc->amr_dev, "polled command timeout\n");
99051974Smsmith    }
99151974Smsmith    return(error);
99251974Smsmith}
99351974Smsmith
99451974Smsmith/********************************************************************************
995107756Semoore * Take a command, submit it to the controller and busy-wait for it to return.
996107756Semoore * Returns nonzero on error.  Can be safely called with interrupts enabled.
997107756Semoore */
998107756Semoorestatic int
999107756Semooreamr_quartz_poll_command(struct amr_command *ac)
1000107756Semoore{
1001107756Semoore    struct amr_softc	*sc = ac->ac_sc;
1002107756Semoore    int			s;
1003109031Semoore    int			error,count;
1004107756Semoore
1005107756Semoore    debug_called(2);
1006107756Semoore
1007107756Semoore    /* now we have a slot, we can map the command (unmapped in amr_complete) */
1008107756Semoore    amr_mapcmd(ac);
1009107756Semoore
1010107756Semoore    s = splbio();
1011107756Semoore
1012131394Sps    if ((sc->amr_state & AMR_STATE_CRASHDUMP) == 0) {
1013120988Sps	count=0;
1014120988Sps	while (sc->amr_busyslots) {
1015120988Sps	    tsleep(sc, PRIBIO | PCATCH, "amrpoll", hz);
1016120988Sps	    if(count++>10) {
1017120988Sps		break;
1018120988Sps	    }
1019109031Semoore	}
1020109031Semoore
1021120988Sps	if(sc->amr_busyslots) {
1022120988Sps	    device_printf(sc->amr_dev, "adapter is busy\n");
1023120988Sps	    splx(s);
1024120988Sps	    amr_unmapcmd(ac);
1025120988Sps    	    ac->ac_status=0;
1026120988Sps	    return(1);
1027120988Sps	}
1028107756Semoore    }
1029107756Semoore
1030107756Semoore    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
1031107756Semoore
1032107756Semoore    /* clear the poll/ack fields in the mailbox */
1033107756Semoore    sc->amr_mailbox->mb_ident = 0xFE;
1034107756Semoore    sc->amr_mailbox->mb_nstatus = 0xFF;
1035107756Semoore    sc->amr_mailbox->mb_status = 0xFF;
1036107756Semoore    sc->amr_mailbox->mb_poll = 0;
1037107756Semoore    sc->amr_mailbox->mb_ack = 0;
1038109031Semoore    sc->amr_mailbox->mb_busy = 1;
1039107756Semoore
1040107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
1041107756Semoore
1042107756Semoore    while(sc->amr_mailbox->mb_nstatus == 0xFF);
1043107756Semoore    while(sc->amr_mailbox->mb_status == 0xFF);
1044107827Semoore    ac->ac_status=sc->amr_mailbox->mb_status;
1045107827Semoore    error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0;
1046107756Semoore    while(sc->amr_mailbox->mb_poll != 0x77);
1047107756Semoore    sc->amr_mailbox->mb_poll = 0;
1048107756Semoore    sc->amr_mailbox->mb_ack = 0x77;
1049107756Semoore
1050107756Semoore    /* acknowledge that we have the commands */
1051107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
1052109031Semoore    while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK);
1053107756Semoore
1054107756Semoore    splx(s);
1055107756Semoore
1056107756Semoore    /* unmap the command's data buffer */
1057107756Semoore    amr_unmapcmd(ac);
1058107756Semoore
1059107827Semoore    return(error);
1060107756Semoore}
1061107756Semoore
1062107756Semoore/********************************************************************************
106365245Smsmith * Get a free command slot for a command if it doesn't already have one.
106465245Smsmith *
106565245Smsmith * May be safely called multiple times for a given command.
106651974Smsmith */
106751974Smsmithstatic int
106851974Smsmithamr_getslot(struct amr_command *ac)
106951974Smsmith{
107051974Smsmith    struct amr_softc	*sc = ac->ac_sc;
107165245Smsmith    int			s, slot, limit, error;
107251974Smsmith
107365245Smsmith    debug_called(3);
107465245Smsmith
107565245Smsmith    /* if the command already has a slot, don't try to give it another one */
107665245Smsmith    if (ac->ac_slot != 0)
107765245Smsmith	return(0);
107865245Smsmith
107951974Smsmith    /* enforce slot usage limit */
108051974Smsmith    limit = (ac->ac_flags & AMR_CMD_PRIORITY) ? sc->amr_maxio : sc->amr_maxio - 4;
108165245Smsmith    if (sc->amr_busyslots > limit)
108251974Smsmith	return(EBUSY);
108351974Smsmith
108451974Smsmith    /*
108565245Smsmith     * Allocate a slot.  XXX linear scan is slow
108651974Smsmith     */
108765245Smsmith    error = EBUSY;
108851974Smsmith    s = splbio();
108951974Smsmith    for (slot = 0; slot < sc->amr_maxio; slot++) {
109065245Smsmith	if (sc->amr_busycmd[slot] == NULL) {
109165245Smsmith	    sc->amr_busycmd[slot] = ac;
109265245Smsmith	    sc->amr_busyslots++;
109365245Smsmith	    ac->ac_slot = slot;
109465245Smsmith	    error = 0;
109551974Smsmith	    break;
109665245Smsmith	}
109751974Smsmith    }
109851974Smsmith    splx(s);
109951974Smsmith
110065245Smsmith    return(error);
110151974Smsmith}
110251974Smsmith
110351974Smsmith/********************************************************************************
110465245Smsmith * Map/unmap (ac)'s data in the controller's addressable space as required.
110565245Smsmith *
110665245Smsmith * These functions may be safely called multiple times on a given command.
110751974Smsmith */
110851974Smsmithstatic void
110951974Smsmithamr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
111051974Smsmith{
111151974Smsmith    struct amr_command	*ac = (struct amr_command *)arg;
111251974Smsmith    struct amr_softc	*sc = ac->ac_sc;
111351974Smsmith    struct amr_sgentry	*sg;
111451974Smsmith    int			i;
111569319Smsmith    u_int8_t		*sgc;
111651974Smsmith
111765245Smsmith    debug_called(3);
111851974Smsmith
111951974Smsmith    /* get base address of s/g table */
112051974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
112151974Smsmith
112265245Smsmith    /* save data physical address */
112351974Smsmith    ac->ac_dataphys = segs[0].ds_addr;
112451974Smsmith
112569319Smsmith    /* for AMR_CMD_CONFIG the s/g count goes elsewhere */
112669319Smsmith    if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) {
112769319Smsmith	sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
112869319Smsmith    } else {
112969319Smsmith	sgc = &ac->ac_mailbox.mb_nsgelem;
113069319Smsmith    }
113169319Smsmith
113265245Smsmith    /* decide whether we need to populate the s/g table */
113365245Smsmith    if (nsegments < 2) {
113469319Smsmith	*sgc = 0;
1135105419Semoore	ac->ac_mailbox.mb_nsgelem = 0;
113665245Smsmith	ac->ac_mailbox.mb_physaddr = ac->ac_dataphys;
113765245Smsmith    } else {
1138105419Semoore        ac->ac_mailbox.mb_nsgelem = nsegments;
113969319Smsmith	*sgc = nsegments;
114065245Smsmith	ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
114165245Smsmith	for (i = 0; i < nsegments; i++, sg++) {
114265245Smsmith	    sg->sg_addr = segs[i].ds_addr;
114365245Smsmith	    sg->sg_count = segs[i].ds_len;
114465245Smsmith	}
114565245Smsmith    }
114665245Smsmith}
114765245Smsmith
114865245Smsmithstatic void
114965245Smsmithamr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
115065245Smsmith{
1151105419Semoore    struct amr_command          *ac = (struct amr_command *)arg;
1152105419Semoore    struct amr_softc            *sc = ac->ac_sc;
1153105419Semoore    struct amr_sgentry          *sg;
1154105419Semoore    struct amr_passthrough      *ap = (struct amr_passthrough *)ac->ac_data;
1155106252Semoore    struct amr_ext_passthrough	*aep = (struct amr_ext_passthrough *)ac->ac_data;
1156105419Semoore    int                         i;
115765245Smsmith
115865245Smsmith    /* get base address of s/g table */
115965245Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
116065245Smsmith
1161105419Semoore    /* decide whether we need to populate the s/g table */
1162106225Semoore    if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
1163106225Semoore	if (nsegments < 2) {
1164106225Semoore	    aep->ap_no_sg_elements = 0;
1165106225Semoore	    aep->ap_data_transfer_address =  segs[0].ds_addr;
1166106225Semoore	} else {
1167106225Semoore	    /* save s/g table information in passthrough */
1168106225Semoore	    aep->ap_no_sg_elements = nsegments;
1169106225Semoore	    aep->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1170106225Semoore	    /* populate s/g table (overwrites previous call which mapped the passthrough) */
1171106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1172106225Semoore		sg->sg_addr = segs[i].ds_addr;
1173106225Semoore		sg->sg_count = segs[i].ds_len;
1174106225Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1175106225Semoore	    }
1176106225Semoore	}
1177106225Semoore	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot,
1178106225Semoore	    aep->ap_no_sg_elements, aep->ap_data_transfer_address, ac->ac_dataphys);
1179105419Semoore    } else {
1180106225Semoore	if (nsegments < 2) {
1181106225Semoore	    ap->ap_no_sg_elements = 0;
1182106225Semoore	    ap->ap_data_transfer_address =  segs[0].ds_addr;
1183106225Semoore	} else {
1184106225Semoore	    /* save s/g table information in passthrough */
1185106225Semoore	    ap->ap_no_sg_elements = nsegments;
1186106225Semoore	    ap->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1187106225Semoore	    /* populate s/g table (overwrites previous call which mapped the passthrough) */
1188106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1189105419Semoore		sg->sg_addr = segs[i].ds_addr;
1190105419Semoore		sg->sg_count = segs[i].ds_len;
1191105419Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1192106225Semoore	    }
1193105419Semoore	}
1194106225Semoore	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot,
1195106225Semoore	    ap->ap_no_sg_elements, ap->ap_data_transfer_address, ac->ac_dataphys);
1196105419Semoore    }
119751974Smsmith}
119851974Smsmith
119951974Smsmithstatic void
120051974Smsmithamr_mapcmd(struct amr_command *ac)
120151974Smsmith{
120251974Smsmith    struct amr_softc	*sc = ac->ac_sc;
120351974Smsmith
120469319Smsmith    debug_called(3);
120551974Smsmith
120665245Smsmith    /* if the command involves data at all, and hasn't been mapped */
120765245Smsmith    if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
120865245Smsmith
120965245Smsmith	if (ac->ac_data != NULL) {
121065245Smsmith	    /* map the data buffers into bus space and build the s/g list */
1211105419Semoore	    bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, ac->ac_length,
121265245Smsmith			    amr_setup_dmamap, ac, 0);
121365245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAIN)
121465245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREREAD);
121565245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAOUT)
121665245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREWRITE);
121765245Smsmith	}
121865245Smsmith
121965245Smsmith	if (ac->ac_ccb_data != NULL) {
1220105419Semoore	    bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, ac->ac_ccb_data, ac->ac_ccb_length,
122165245Smsmith			    amr_setup_ccbmap, ac, 0);
122265245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
122365245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREREAD);
122465245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
122565245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREWRITE);
122665245Smsmith	}
122765245Smsmith	ac->ac_flags |= AMR_CMD_MAPPED;
122851974Smsmith    }
122951974Smsmith}
123051974Smsmith
123151974Smsmithstatic void
123251974Smsmithamr_unmapcmd(struct amr_command *ac)
123351974Smsmith{
123451974Smsmith    struct amr_softc	*sc = ac->ac_sc;
123551974Smsmith
123669319Smsmith    debug_called(3);
123751974Smsmith
123865245Smsmith    /* if the command involved data at all and was mapped */
123965245Smsmith    if (ac->ac_flags & AMR_CMD_MAPPED) {
124051974Smsmith
124165245Smsmith	if (ac->ac_data != NULL) {
124265245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAIN)
124365245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD);
124465245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAOUT)
124565245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTWRITE);
124665245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
124765245Smsmith	}
124865245Smsmith
124965245Smsmith	if (ac->ac_ccb_data != NULL) {
125065245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
125165245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTREAD);
125265245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
125365245Smsmith		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTWRITE);
125465245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap);
125565245Smsmith	}
125665245Smsmith	ac->ac_flags &= ~AMR_CMD_MAPPED;
125751974Smsmith    }
125851974Smsmith}
125951974Smsmith
126051974Smsmith/********************************************************************************
126165245Smsmith * Take a command and give it to the controller, returns 0 if successful, or
126265245Smsmith * EBUSY if the command should be retried later.
126351974Smsmith */
126451974Smsmithstatic int
126551974Smsmithamr_start(struct amr_command *ac)
126651974Smsmith{
126751974Smsmith    struct amr_softc	*sc = ac->ac_sc;
126858883Smsmith    int			done, s, i;
1269105419Semoore
127069319Smsmith    debug_called(3);
127151974Smsmith
127265245Smsmith    /* mark command as busy so that polling consumer can tell */
127365245Smsmith    ac->ac_flags |= AMR_CMD_BUSY;
127465245Smsmith
127565245Smsmith    /* get a command slot (freed in amr_done) */
127665245Smsmith    if (amr_getslot(ac))
127765245Smsmith	return(EBUSY);
127865245Smsmith
127965245Smsmith    /* now we have a slot, we can map the command (unmapped in amr_complete) */
128065245Smsmith    amr_mapcmd(ac);
128165245Smsmith
128265245Smsmith    /* mark the new mailbox we are going to copy in as busy */
128365245Smsmith    ac->ac_mailbox.mb_busy = 1;
128465245Smsmith
128565245Smsmith    /* clear the poll/ack fields in the mailbox */
128665245Smsmith    sc->amr_mailbox->mb_poll = 0;
128765245Smsmith    sc->amr_mailbox->mb_ack = 0;
128865245Smsmith
128951974Smsmith    /*
129051974Smsmith     * Save the slot number so that we can locate this command when complete.
129151974Smsmith     * Note that ident = 0 seems to be special, so we don't use it.
129251974Smsmith     */
129351974Smsmith    ac->ac_mailbox.mb_ident = ac->ac_slot + 1;
129451974Smsmith
129558883Smsmith    /*
129665245Smsmith     * Spin waiting for the mailbox, give up after ~1 second.  We expect the
129765245Smsmith     * controller to be able to handle our I/O.
129865245Smsmith     *
129965245Smsmith     * XXX perhaps we should wait for less time, and count on the deferred command
130065245Smsmith     * handling to deal with retries?
130158883Smsmith     */
130269319Smsmith    debug(4, "wait for mailbox");
130358883Smsmith    for (i = 10000, done = 0; (i > 0) && !done; i--) {
130451974Smsmith	s = splbio();
130551974Smsmith
130651974Smsmith	/* is the mailbox free? */
130751974Smsmith	if (sc->amr_mailbox->mb_busy == 0) {
130869319Smsmith	    debug(4, "got mailbox");
130951974Smsmith	    sc->amr_mailbox64->mb64_segment = 0;
131065245Smsmith	    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
131151974Smsmith	    done = 1;
131251974Smsmith
131365245Smsmith	    /* not free, spin waiting */
131451974Smsmith	} else {
131569319Smsmith	    debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy);
131658883Smsmith	    /* this is somewhat ugly */
131758883Smsmith	    DELAY(100);
131851974Smsmith	}
131958883Smsmith	splx(s);	/* drop spl to allow completion interrupts */
132051974Smsmith    }
132165245Smsmith
132265245Smsmith    /*
132365245Smsmith     * Now give the command to the controller
132465245Smsmith     */
132551974Smsmith    if (done) {
132665245Smsmith	if (sc->amr_submit_command(sc)) {
132765245Smsmith	    /* the controller wasn't ready to take the command, forget that we tried to post it */
132865245Smsmith	    sc->amr_mailbox->mb_busy = 0;
132965245Smsmith	    return(EBUSY);
133065245Smsmith	}
133169319Smsmith	debug(3, "posted command");
133251974Smsmith	return(0);
133351974Smsmith    }
133451974Smsmith
133551974Smsmith    /*
133665245Smsmith     * The controller wouldn't take the command.  Return the command as busy
133765245Smsmith     * so that it is retried later.
133851974Smsmith     */
133965245Smsmith    return(EBUSY);
134051974Smsmith}
134151974Smsmith
134251974Smsmith/********************************************************************************
134351974Smsmith * Extract one or more completed commands from the controller (sc)
134451974Smsmith *
134552543Smsmith * Returns nonzero if any commands on the work queue were marked as completed.
134651974Smsmith */
134765245Smsmithint
134851974Smsmithamr_done(struct amr_softc *sc)
134951974Smsmith{
135051974Smsmith    struct amr_command	*ac;
135151974Smsmith    struct amr_mailbox	mbox;
135265245Smsmith    int			i, idx, result;
135351974Smsmith
135469319Smsmith    debug_called(3);
135551974Smsmith
135651974Smsmith    /* See if there's anything for us to do */
135751974Smsmith    result = 0;
135851974Smsmith
135958883Smsmith    /* loop collecting completed commands */
136058883Smsmith    for (;;) {
136158883Smsmith	/* poll for a completed command's identifier and status */
136258883Smsmith	if (sc->amr_get_work(sc, &mbox)) {
136358883Smsmith	    result = 1;
136458883Smsmith
136558883Smsmith	    /* iterate over completed commands in this result */
136658883Smsmith	    for (i = 0; i < mbox.mb_nstatus; i++) {
136758883Smsmith		/* get pointer to busy command */
136858883Smsmith		idx = mbox.mb_completed[i] - 1;
136958883Smsmith		ac = sc->amr_busycmd[idx];
137051974Smsmith
137158883Smsmith		/* really a busy command? */
137258883Smsmith		if (ac != NULL) {
137358883Smsmith
137458883Smsmith		    /* pull the command from the busy index */
137558883Smsmith		    sc->amr_busycmd[idx] = NULL;
137665245Smsmith		    sc->amr_busyslots--;
137751974Smsmith
137865245Smsmith		    /* save status for later use */
137965245Smsmith		    ac->ac_status = mbox.mb_status;
138065245Smsmith		    amr_enqueue_completed(ac);
138165245Smsmith		    debug(3, "completed command with status %x", mbox.mb_status);
138265245Smsmith		} else {
138365245Smsmith		    device_printf(sc->amr_dev, "bad slot %d completed\n", idx);
138451974Smsmith		}
138551974Smsmith	    }
138658883Smsmith	} else {
138765245Smsmith	    break;	/* no work */
138851974Smsmith	}
138951974Smsmith    }
139058883Smsmith
139158883Smsmith    /* if we've completed any commands, try posting some more */
139258883Smsmith    if (result)
139358883Smsmith	amr_startio(sc);
139458883Smsmith
139558883Smsmith    /* handle completion and timeouts */
139665245Smsmith#if __FreeBSD_version >= 500005
139765245Smsmith    if (sc->amr_state & AMR_STATE_INTEN)
1398111528Sscottl	taskqueue_enqueue(taskqueue_swi_giant, &sc->amr_task_complete);
139965245Smsmith    else
140065245Smsmith#endif
140165245Smsmith	amr_complete(sc, 0);
140258883Smsmith
140351974Smsmith    return(result);
140451974Smsmith}
140551974Smsmith
140651974Smsmith/********************************************************************************
140751974Smsmith * Do completion processing on done commands on (sc)
140851974Smsmith */
140951974Smsmithstatic void
141065245Smsmithamr_complete(void *context, int pending)
141151974Smsmith{
141265245Smsmith    struct amr_softc	*sc = (struct amr_softc *)context;
141365245Smsmith    struct amr_command	*ac;
141451974Smsmith
141569319Smsmith    debug_called(3);
141651974Smsmith
141765245Smsmith    /* pull completed commands off the queue */
141865245Smsmith    for (;;) {
141965245Smsmith	ac = amr_dequeue_completed(sc);
142065245Smsmith	if (ac == NULL)
142165245Smsmith	    break;
142258883Smsmith
142365245Smsmith	/* unmap the command's data buffer */
142465245Smsmith	amr_unmapcmd(ac);
142551974Smsmith
142665245Smsmith	/* unbusy the command */
142765245Smsmith	ac->ac_flags &= ~AMR_CMD_BUSY;
142851974Smsmith
142965245Smsmith	/*
143065245Smsmith	 * Is there a completion handler?
143165245Smsmith	 */
143265245Smsmith	if (ac->ac_complete != NULL) {
143365245Smsmith	    ac->ac_complete(ac);
143465245Smsmith
143551974Smsmith	    /*
143665245Smsmith	     * Is someone sleeping on this one?
143751974Smsmith	     */
143865245Smsmith	} else if (ac->ac_flags & AMR_CMD_SLEEP) {
143965245Smsmith	    wakeup(ac);
144051974Smsmith	}
1441109031Semoore
1442109031Semoore	if(!sc->amr_busyslots) {
1443109031Semoore	    wakeup(sc);
1444109031Semoore	}
144551974Smsmith    }
144651974Smsmith}
144751974Smsmith
144851974Smsmith/********************************************************************************
144951974Smsmith ********************************************************************************
145051974Smsmith                                                        Command Buffer Management
145151974Smsmith ********************************************************************************
145251974Smsmith ********************************************************************************/
145351974Smsmith
145451974Smsmith/********************************************************************************
145551974Smsmith * Get a new command buffer.
145651974Smsmith *
145751974Smsmith * This may return NULL in low-memory cases.
145851974Smsmith *
145951974Smsmith * If possible, we recycle a command buffer that's been used before.
146051974Smsmith */
146165245Smsmithstruct amr_command *
146251974Smsmithamr_alloccmd(struct amr_softc *sc)
146351974Smsmith{
146451974Smsmith    struct amr_command	*ac;
146551974Smsmith
146665245Smsmith    debug_called(3);
146751974Smsmith
146865245Smsmith    ac = amr_dequeue_free(sc);
146951974Smsmith    if (ac == NULL) {
147065245Smsmith	amr_alloccmd_cluster(sc);
147165245Smsmith	ac = amr_dequeue_free(sc);
147251974Smsmith    }
147365245Smsmith    if (ac == NULL)
147465245Smsmith	return(NULL);
147565245Smsmith
147665245Smsmith    /* clear out significant fields */
147765245Smsmith    ac->ac_slot = 0;
147865245Smsmith    ac->ac_status = 0;
147951974Smsmith    bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox));
148065245Smsmith    ac->ac_flags = 0;
148165245Smsmith    ac->ac_bio = NULL;
148265245Smsmith    ac->ac_data = NULL;
148365245Smsmith    ac->ac_ccb_data = NULL;
148465245Smsmith    ac->ac_complete = NULL;
148551974Smsmith    return(ac);
148651974Smsmith}
148751974Smsmith
148851974Smsmith/********************************************************************************
148951974Smsmith * Release a command buffer for recycling.
149051974Smsmith */
149165245Smsmithvoid
149251974Smsmithamr_releasecmd(struct amr_command *ac)
149351974Smsmith{
149465245Smsmith    debug_called(3);
149551974Smsmith
149665245Smsmith    amr_enqueue_free(ac);
149751974Smsmith}
149851974Smsmith
149951974Smsmith/********************************************************************************
150065245Smsmith * Allocate a new command cluster and initialise it.
150151974Smsmith */
1502104094Sphkstatic void
150365245Smsmithamr_alloccmd_cluster(struct amr_softc *sc)
150451974Smsmith{
150565245Smsmith    struct amr_command_cluster	*acc;
150665245Smsmith    struct amr_command		*ac;
150765245Smsmith    int				s, i;
150851974Smsmith
150965245Smsmith    acc = malloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_NOWAIT);
151065245Smsmith    if (acc != NULL) {
151165245Smsmith	s = splbio();
151265245Smsmith	TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link);
151365245Smsmith	splx(s);
151465245Smsmith	for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
151565245Smsmith	    ac = &acc->acc_command[i];
151665245Smsmith	    bzero(ac, sizeof(*ac));
151765245Smsmith	    ac->ac_sc = sc;
151865245Smsmith	    if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) &&
151965245Smsmith		!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap))
152065245Smsmith		amr_releasecmd(ac);
152165245Smsmith	}
152265245Smsmith    }
152351974Smsmith}
152451974Smsmith
152551974Smsmith/********************************************************************************
152665245Smsmith * Free a command cluster
152765245Smsmith */
1528104094Sphkstatic void
152965245Smsmithamr_freecmd_cluster(struct amr_command_cluster *acc)
153065245Smsmith{
153165245Smsmith    struct amr_softc	*sc = acc->acc_command[0].ac_sc;
153265245Smsmith    int			i;
153365245Smsmith
153465245Smsmith    for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++)
153565245Smsmith	bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap);
153665245Smsmith    free(acc, M_DEVBUF);
153765245Smsmith}
153865245Smsmith
153965245Smsmith/********************************************************************************
154051974Smsmith ********************************************************************************
154151974Smsmith                                                         Interface-specific Shims
154251974Smsmith ********************************************************************************
154351974Smsmith ********************************************************************************/
154451974Smsmith
154551974Smsmith/********************************************************************************
154651974Smsmith * Tell the controller that the mailbox contains a valid command
154751974Smsmith */
154865245Smsmithstatic int
154951974Smsmithamr_quartz_submit_command(struct amr_softc *sc)
155051974Smsmith{
155165245Smsmith    debug_called(3);
155251974Smsmith
155365245Smsmith    if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT)
155465245Smsmith	return(EBUSY);
155551974Smsmith    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
155665245Smsmith    return(0);
155751974Smsmith}
155851974Smsmith
155965245Smsmithstatic int
156051974Smsmithamr_std_submit_command(struct amr_softc *sc)
156151974Smsmith{
156265245Smsmith    debug_called(3);
156351974Smsmith
156465245Smsmith    if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG)
156565245Smsmith	return(EBUSY);
156651974Smsmith    AMR_SPOST_COMMAND(sc);
156765245Smsmith    return(0);
156851974Smsmith}
156951974Smsmith
157051974Smsmith/********************************************************************************
157151974Smsmith * Claim any work that the controller has completed; acknowledge completion,
157251974Smsmith * save details of the completion in (mbsave)
157351974Smsmith */
157451974Smsmithstatic int
157551974Smsmithamr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
157651974Smsmith{
157751974Smsmith    int		s, worked;
157851974Smsmith    u_int32_t	outd;
157951974Smsmith
158065245Smsmith    debug_called(3);
158165245Smsmith
158251974Smsmith    worked = 0;
158351974Smsmith    s = splbio();
158451974Smsmith
158551974Smsmith    /* work waiting for us? */
158651974Smsmith    if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) {
158751974Smsmith
158851974Smsmith	/* save mailbox, which contains a list of completed commands */
158965245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
159051974Smsmith
159165245Smsmith	/* acknowledge interrupt */
159265245Smsmith	AMR_QPUT_ODB(sc, AMR_QODB_READY);
159365245Smsmith
159451974Smsmith	/* acknowledge that we have the commands */
159551974Smsmith	AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
159665245Smsmith
159765763Smsmith#ifndef AMR_QUARTZ_GOFASTER
159865245Smsmith	/*
159965245Smsmith	 * This waits for the controller to notice that we've taken the
160065245Smsmith	 * command from it.  It's very inefficient, and we shouldn't do it,
160165245Smsmith	 * but if we remove this code, we stop completing commands under
160265245Smsmith	 * load.
160365245Smsmith	 *
160465245Smsmith	 * Peter J says we shouldn't do this.  The documentation says we
160565245Smsmith	 * should.  Who is right?
160665245Smsmith	 */
160751974Smsmith	while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
160851974Smsmith	    ;				/* XXX aiee! what if it dies? */
160965245Smsmith#endif
161065245Smsmith
161151974Smsmith	worked = 1;			/* got some work */
161251974Smsmith    }
161351974Smsmith
161451974Smsmith    splx(s);
161551974Smsmith    return(worked);
161651974Smsmith}
161751974Smsmith
161851974Smsmithstatic int
161951974Smsmithamr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
162051974Smsmith{
162151974Smsmith    int		s, worked;
162251974Smsmith    u_int8_t	istat;
162351974Smsmith
162465245Smsmith    debug_called(3);
162551974Smsmith
162651974Smsmith    worked = 0;
162751974Smsmith    s = splbio();
162851974Smsmith
162951974Smsmith    /* check for valid interrupt status */
163051974Smsmith    istat = AMR_SGET_ISTAT(sc);
163151974Smsmith    if ((istat & AMR_SINTR_VALID) != 0) {
163251974Smsmith	AMR_SPUT_ISTAT(sc, istat);	/* ack interrupt status */
163351974Smsmith
163451974Smsmith	/* save mailbox, which contains a list of completed commands */
163565245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
163651974Smsmith
163751974Smsmith	AMR_SACK_INTERRUPT(sc);		/* acknowledge we have the mailbox */
163851974Smsmith	worked = 1;
163951974Smsmith    }
164051974Smsmith
164151974Smsmith    splx(s);
164251974Smsmith    return(worked);
164351974Smsmith}
164451974Smsmith
164551974Smsmith/********************************************************************************
164651974Smsmith * Notify the controller of the mailbox location.
164751974Smsmith */
164851974Smsmithstatic void
164951974Smsmithamr_std_attach_mailbox(struct amr_softc *sc)
165051974Smsmith{
165151974Smsmith
165251974Smsmith    /* program the mailbox physical address */
165351974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_0, sc->amr_mailboxphys         & 0xff);
165451974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_1, (sc->amr_mailboxphys >>  8) & 0xff);
165551974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_2, (sc->amr_mailboxphys >> 16) & 0xff);
165651974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_3, (sc->amr_mailboxphys >> 24) & 0xff);
165751974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_ENABLE, AMR_SMBOX_ADDR);
165851974Smsmith
165951974Smsmith    /* clear any outstanding interrupt and enable interrupts proper */
166051974Smsmith    AMR_SACK_INTERRUPT(sc);
166151974Smsmith    AMR_SENABLE_INTR(sc);
166251974Smsmith}
166351974Smsmith
166465245Smsmith#ifdef AMR_BOARD_INIT
166551974Smsmith/********************************************************************************
166665245Smsmith * Initialise the controller
166765245Smsmith */
166865245Smsmithstatic int
166965245Smsmithamr_quartz_init(struct amr_softc *sc)
167065245Smsmith{
167165245Smsmith    int		status, ostatus;
167265245Smsmith
167365245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_QGET_INITSTATUS(sc));
167465245Smsmith
167565245Smsmith    AMR_QRESET(sc);
167665245Smsmith
167765245Smsmith    ostatus = 0xff;
167865245Smsmith    while ((status = AMR_QGET_INITSTATUS(sc)) != AMR_QINIT_DONE) {
167965245Smsmith	if (status != ostatus) {
168065245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_qinit, status));
168165245Smsmith	    ostatus = status;
168265245Smsmith	}
168365245Smsmith	switch (status) {
168465245Smsmith	case AMR_QINIT_NOMEM:
168565245Smsmith	    return(ENOMEM);
168665245Smsmith
168765245Smsmith	case AMR_QINIT_SCAN:
168865245Smsmith	    /* XXX we could print channel/target here */
168965245Smsmith	    break;
169065245Smsmith	}
169165245Smsmith    }
169265245Smsmith    return(0);
169365245Smsmith}
169465245Smsmith
169565245Smsmithstatic int
169665245Smsmithamr_std_init(struct amr_softc *sc)
169765245Smsmith{
169865245Smsmith    int		status, ostatus;
169965245Smsmith
170065245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_SGET_INITSTATUS(sc));
170165245Smsmith
170265245Smsmith    AMR_SRESET(sc);
170365245Smsmith
170465245Smsmith    ostatus = 0xff;
170565245Smsmith    while ((status = AMR_SGET_INITSTATUS(sc)) != AMR_SINIT_DONE) {
170665245Smsmith	if (status != ostatus) {
170765245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_sinit, status));
170865245Smsmith	    ostatus = status;
170965245Smsmith	}
171065245Smsmith	switch (status) {
171165245Smsmith	case AMR_SINIT_NOMEM:
171265245Smsmith	    return(ENOMEM);
171365245Smsmith
171465245Smsmith	case AMR_SINIT_INPROG:
171565245Smsmith	    /* XXX we could print channel/target here? */
171665245Smsmith	    break;
171765245Smsmith	}
171865245Smsmith    }
171965245Smsmith    return(0);
172065245Smsmith}
172165245Smsmith#endif
172265245Smsmith
172365245Smsmith/********************************************************************************
172451974Smsmith ********************************************************************************
172551974Smsmith                                                                        Debugging
172651974Smsmith ********************************************************************************
172751974Smsmith ********************************************************************************/
172851974Smsmith
172951974Smsmith/********************************************************************************
173065245Smsmith * Identify the controller and print some information about it.
173165245Smsmith */
173265245Smsmithstatic void
173365245Smsmithamr_describe_controller(struct amr_softc *sc)
173465245Smsmith{
173565245Smsmith    struct amr_prodinfo	*ap;
173665245Smsmith    struct amr_enquiry	*ae;
173765245Smsmith    char		*prod;
173865245Smsmith
173965245Smsmith    /*
174065245Smsmith     * Try to get 40LD product info, which tells us what the card is labelled as.
174165245Smsmith     */
174265245Smsmith    if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) {
1743105419Semoore	device_printf(sc->amr_dev, "<LSILogic %.80s> Firmware %.16s, BIOS %.16s, %dMB RAM\n",
174465245Smsmith		      ap->ap_product, ap->ap_firmware, ap->ap_bios,
174565245Smsmith		      ap->ap_memsize);
174665245Smsmith
174765245Smsmith	free(ap, M_DEVBUF);
174865245Smsmith	return;
174965245Smsmith    }
175065245Smsmith
175165245Smsmith    /*
175265245Smsmith     * Try 8LD extended ENQUIRY to get controller signature, and use lookup table.
175365245Smsmith     */
175465245Smsmith    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) {
175565245Smsmith	prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature);
175665245Smsmith
175765245Smsmith    } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) {
175865245Smsmith
175965245Smsmith	/*
176065245Smsmith	 * Try to work it out based on the PCI signatures.
176165245Smsmith	 */
176265245Smsmith	switch (pci_get_device(sc->amr_dev)) {
176365245Smsmith	case 0x9010:
176465245Smsmith	    prod = "Series 428";
176565245Smsmith	    break;
176665245Smsmith	case 0x9060:
176765245Smsmith	    prod = "Series 434";
176865245Smsmith	    break;
176965245Smsmith	default:
177065245Smsmith	    prod = "unknown controller";
177165245Smsmith	    break;
177265245Smsmith	}
177365245Smsmith    } else {
177465245Smsmith	prod = "unsupported controller";
177565245Smsmith    }
177674936Shm
177774936Shm    /*
177874936Shm     * HP NetRaid controllers have a special encoding of the firmware and
177974936Shm     * BIOS versions. The AMI version seems to have it as strings whereas
178074936Shm     * the HP version does it with a leading uppercase character and two
178174936Shm     * binary numbers.
178274936Shm     */
178374936Shm
178474936Shm    if(ae->ae_adapter.aa_firmware[2] >= 'A' &&
178574936Shm       ae->ae_adapter.aa_firmware[2] <= 'Z' &&
178674936Shm       ae->ae_adapter.aa_firmware[1] <  ' ' &&
178774936Shm       ae->ae_adapter.aa_firmware[0] <  ' ' &&
178874936Shm       ae->ae_adapter.aa_bios[2] >= 'A'     &&
178974936Shm       ae->ae_adapter.aa_bios[2] <= 'Z'     &&
179074936Shm       ae->ae_adapter.aa_bios[1] <  ' '     &&
179174936Shm       ae->ae_adapter.aa_bios[0] <  ' ') {
179274936Shm
179374936Shm	/* this looks like we have an HP NetRaid version of the MegaRaid */
179474936Shm
179574936Shm    	if(ae->ae_signature == AMR_SIG_438) {
1796108470Sschweikh    		/* the AMI 438 is a NetRaid 3si in HP-land */
179774936Shm    		prod = "HP NetRaid 3si";
179874936Shm    	}
179974936Shm
180074936Shm	device_printf(sc->amr_dev, "<%s> Firmware %c.%02d.%02d, BIOS %c.%02d.%02d, %dMB RAM\n",
180174936Shm		      prod, ae->ae_adapter.aa_firmware[2],
180274936Shm		      ae->ae_adapter.aa_firmware[1],
180374936Shm		      ae->ae_adapter.aa_firmware[0],
180474936Shm		      ae->ae_adapter.aa_bios[2],
180574936Shm		      ae->ae_adapter.aa_bios[1],
180674936Shm		      ae->ae_adapter.aa_bios[0],
180774936Shm		      ae->ae_adapter.aa_memorysize);
180874936Shm    } else {
180974936Shm	device_printf(sc->amr_dev, "<%s> Firmware %.4s, BIOS %.4s, %dMB RAM\n",
181074936Shm		      prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios,
181174936Shm		      ae->ae_adapter.aa_memorysize);
181274936Shm    }
181365245Smsmith    free(ae, M_DEVBUF);
181465245Smsmith}
181565245Smsmith
1816120988Spsint
1817120988Spsamr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks)
1818120988Sps{
1819120988Sps    struct amr_command	*ac;
1820120988Sps    int			error = EIO;
1821120988Sps
1822120988Sps    debug_called(1);
1823120988Sps
1824131394Sps    sc->amr_state |= AMR_STATE_CRASHDUMP;
1825120988Sps
1826120988Sps    /* get ourselves a command buffer */
1827120988Sps    if ((ac = amr_alloccmd(sc)) == NULL)
1828120988Sps	goto out;
1829120988Sps    /* set command flags */
1830120988Sps    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
1831120988Sps
1832120988Sps    /* point the command at our data */
1833120988Sps    ac->ac_data = data;
1834120988Sps    ac->ac_length = blks * AMR_BLKSIZE;
1835120988Sps
1836120988Sps    /* build the command proper */
1837120988Sps    ac->ac_mailbox.mb_command 	= AMR_CMD_LWRITE;
1838120988Sps    ac->ac_mailbox.mb_blkcount	= blks;
1839120988Sps    ac->ac_mailbox.mb_lba	= lba;
1840120988Sps    ac->ac_mailbox.mb_drive	= unit;
1841120988Sps
1842120988Sps    /* can't assume that interrupts are going to work here, so play it safe */
1843120988Sps    if (sc->amr_poll_command(ac))
1844120988Sps	goto out;
1845120988Sps    error = ac->ac_status;
1846120988Sps
1847120988Sps out:
1848120988Sps    if (ac != NULL)
1849120988Sps	amr_releasecmd(ac);
1850120988Sps
1851131394Sps    sc->amr_state &= ~AMR_STATE_CRASHDUMP;
1852120988Sps    return (error);
1853120988Sps}
1854120988Sps
1855120988Sps
1856120988Sps
185765245Smsmith#ifdef AMR_DEBUG
185865245Smsmith/********************************************************************************
185951974Smsmith * Print the command (ac) in human-readable format
186051974Smsmith */
1861107756Semoore#if 0
186251974Smsmithstatic void
186351974Smsmithamr_printcommand(struct amr_command *ac)
186451974Smsmith{
186551974Smsmith    struct amr_softc	*sc = ac->ac_sc;
186651974Smsmith    struct amr_sgentry	*sg;
186751974Smsmith    int			i;
186851974Smsmith
186951974Smsmith    device_printf(sc->amr_dev, "cmd %x  ident %d  drive %d\n",
187051974Smsmith		  ac->ac_mailbox.mb_command, ac->ac_mailbox.mb_ident, ac->ac_mailbox.mb_drive);
187151974Smsmith    device_printf(sc->amr_dev, "blkcount %d  lba %d\n",
187251974Smsmith		  ac->ac_mailbox.mb_blkcount, ac->ac_mailbox.mb_lba);
187354512Speter    device_printf(sc->amr_dev, "virtaddr %p  length %lu\n", ac->ac_data, (unsigned long)ac->ac_length);
187458883Smsmith    device_printf(sc->amr_dev, "sg physaddr %08x  nsg %d\n",
187551974Smsmith		  ac->ac_mailbox.mb_physaddr, ac->ac_mailbox.mb_nsgelem);
187665245Smsmith    device_printf(sc->amr_dev, "ccb %p  bio %p\n", ac->ac_ccb_data, ac->ac_bio);
187751974Smsmith
187851974Smsmith    /* get base address of s/g table */
187951974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
188051974Smsmith    for (i = 0; i < ac->ac_mailbox.mb_nsgelem; i++, sg++)
188151974Smsmith	device_printf(sc->amr_dev, "  %x/%d\n", sg->sg_addr, sg->sg_count);
188251974Smsmith}
188365245Smsmith#endif
1884107756Semoore#endif
1885