amr.c revision 148499
151974Smsmith/*-
265245Smsmith * Copyright (c) 1999,2000 Michael Smith
365245Smsmith * Copyright (c) 2000 BSDi
4140687Sscottl * Copyright (c) 2005 Scott Long
551974Smsmith * All rights reserved.
651974Smsmith *
751974Smsmith * Redistribution and use in source and binary forms, with or without
851974Smsmith * modification, are permitted provided that the following conditions
951974Smsmith * are met:
1051974Smsmith * 1. Redistributions of source code must retain the above copyright
1151974Smsmith *    notice, this list of conditions and the following disclaimer.
1251974Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1351974Smsmith *    notice, this list of conditions and the following disclaimer in the
1451974Smsmith *    documentation and/or other materials provided with the distribution.
1551974Smsmith *
1651974Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1751974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1851974Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1951974Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2051974Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2151974Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2251974Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2351974Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2451974Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2551974Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2651974Smsmith * SUCH DAMAGE.
27119418Sobrien */
28139749Simp/*-
29106225Semoore * Copyright (c) 2002 Eric Moore
30140688Sscottl * Copyright (c) 2002, 2004 LSI Logic Corporation
31106225Semoore * All rights reserved.
32106225Semoore *
33106225Semoore * Redistribution and use in source and binary forms, with or without
34106225Semoore * modification, are permitted provided that the following conditions
35106225Semoore * are met:
36106225Semoore * 1. Redistributions of source code must retain the above copyright
37106225Semoore *    notice, this list of conditions and the following disclaimer.
38106225Semoore * 2. Redistributions in binary form must reproduce the above copyright
39106225Semoore *    notice, this list of conditions and the following disclaimer in the
40106225Semoore *    documentation and/or other materials provided with the distribution.
41105419Semoore * 3. The party using or redistributing the source code and binary forms
42106225Semoore *    agrees to the disclaimer below and the terms and conditions set forth
43105419Semoore *    herein.
44105419Semoore *
45106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48106225Semoore * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55106225Semoore * SUCH DAMAGE.
5651974Smsmith */
5751974Smsmith
58119418Sobrien#include <sys/cdefs.h>
59119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/amr/amr.c 148499 2005-07-29 01:53:45Z ps $");
60119418Sobrien
6151974Smsmith/*
6265245Smsmith * Driver for the AMI MegaRaid family of controllers.
6351974Smsmith */
6451974Smsmith
6551974Smsmith#include <sys/param.h>
6651974Smsmith#include <sys/systm.h>
6751974Smsmith#include <sys/malloc.h>
6851974Smsmith#include <sys/kernel.h>
6951974Smsmith
7065245Smsmith#include <dev/amr/amr_compat.h>
7151974Smsmith#include <sys/bus.h>
7251974Smsmith#include <sys/conf.h>
7365245Smsmith#include <sys/stat.h>
7451974Smsmith
7565245Smsmith#include <machine/bus.h>
7651974Smsmith#include <machine/resource.h>
7751974Smsmith#include <sys/rman.h>
7851974Smsmith
79119277Simp#include <dev/pci/pcireg.h>
80119277Simp#include <dev/pci/pcivar.h>
8165245Smsmith
8251974Smsmith#include <dev/amr/amrio.h>
8351974Smsmith#include <dev/amr/amrreg.h>
8451974Smsmith#include <dev/amr/amrvar.h>
8565245Smsmith#define AMR_DEFINE_TABLES
8665245Smsmith#include <dev/amr/amr_tables.h>
8751974Smsmith
8865245Smsmithstatic d_open_t         amr_open;
8965245Smsmithstatic d_close_t        amr_close;
9065245Smsmithstatic d_ioctl_t        amr_ioctl;
9165245Smsmith
9251974Smsmithstatic struct cdevsw amr_cdevsw = {
93126080Sphk	.d_version =	D_VERSION,
94126080Sphk	.d_flags =	D_NEEDGIANT,
95111815Sphk	.d_open =	amr_open,
96111815Sphk	.d_close =	amr_close,
97111815Sphk	.d_ioctl =	amr_ioctl,
98111815Sphk	.d_name =	"amr",
9951974Smsmith};
10051974Smsmith
10165245Smsmith/*
10265245Smsmith * Initialisation, bus interface.
10365245Smsmith */
10465245Smsmithstatic void	amr_startup(void *arg);
10551974Smsmith
10651974Smsmith/*
10751974Smsmith * Command wrappers
10851974Smsmith */
10965245Smsmithstatic int	amr_query_controller(struct amr_softc *sc);
11065245Smsmithstatic void	*amr_enquiry(struct amr_softc *sc, size_t bufsize,
11165245Smsmith			     u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual);
11265245Smsmithstatic void	amr_completeio(struct amr_command *ac);
113106225Semoorestatic int	amr_support_ext_cdb(struct amr_softc *sc);
11451974Smsmith
11551974Smsmith/*
11665245Smsmith * Command buffer allocation.
11751974Smsmith */
11865245Smsmithstatic void	amr_alloccmd_cluster(struct amr_softc *sc);
11965245Smsmithstatic void	amr_freecmd_cluster(struct amr_command_cluster *acc);
12051974Smsmith
12151974Smsmith/*
12265245Smsmith * Command processing.
12351974Smsmith */
12465245Smsmithstatic int	amr_bio_command(struct amr_softc *sc, struct amr_command **acp);
125138422Sscottlstatic int	amr_wait_command(struct amr_command *ac) __unused;
12665245Smsmithstatic int	amr_getslot(struct amr_command *ac);
127138422Sscottlstatic int	amr_mapcmd(struct amr_command *ac);
12865245Smsmithstatic void	amr_unmapcmd(struct amr_command *ac);
12965245Smsmithstatic int	amr_start(struct amr_command *ac);
130138422Sscottlstatic int	amr_start1(struct amr_softc *sc, struct amr_command *ac);
13165245Smsmithstatic void	amr_complete(void *context, int pending);
132138422Sscottlstatic void	amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
133138422Sscottlstatic void	amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
13451974Smsmith
13551974Smsmith/*
13658883Smsmith * Status monitoring
13758883Smsmith */
13865245Smsmithstatic void	amr_periodic(void *data);
13958883Smsmith
14058883Smsmith/*
14151974Smsmith * Interface-specific shims
14251974Smsmith */
14365245Smsmithstatic int	amr_quartz_submit_command(struct amr_softc *sc);
14465245Smsmithstatic int	amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
145107756Semoorestatic int	amr_quartz_poll_command(struct amr_command *ac);
146138422Sscottlstatic int	amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac);
14751974Smsmith
14865245Smsmithstatic int	amr_std_submit_command(struct amr_softc *sc);
14965245Smsmithstatic int	amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
150107756Semoorestatic int	amr_std_poll_command(struct amr_command *ac);
15165245Smsmithstatic void	amr_std_attach_mailbox(struct amr_softc *sc);
15251974Smsmith
15365245Smsmith#ifdef AMR_BOARD_INIT
15465245Smsmithstatic int	amr_quartz_init(struct amr_softc *sc);
15565245Smsmithstatic int	amr_std_init(struct amr_softc *sc);
15665245Smsmith#endif
15765245Smsmith
15851974Smsmith/*
15951974Smsmith * Debugging
16051974Smsmith */
16165245Smsmithstatic void	amr_describe_controller(struct amr_softc *sc);
16265245Smsmith#ifdef AMR_DEBUG
163107756Semoore#if 0
16465245Smsmithstatic void	amr_printcommand(struct amr_command *ac);
16565245Smsmith#endif
166107756Semoore#endif
16751974Smsmith
16851974Smsmith/********************************************************************************
16951974Smsmith ********************************************************************************
17065245Smsmith                                                                      Inline Glue
17151974Smsmith ********************************************************************************
17251974Smsmith ********************************************************************************/
17351974Smsmith
17451974Smsmith/********************************************************************************
17565245Smsmith ********************************************************************************
17665245Smsmith                                                                Public Interfaces
17765245Smsmith ********************************************************************************
17865245Smsmith ********************************************************************************/
17951974Smsmith
18051974Smsmith/********************************************************************************
18151974Smsmith * Initialise the controller and softc.
18251974Smsmith */
18351974Smsmithint
18451974Smsmithamr_attach(struct amr_softc *sc)
18551974Smsmith{
18651974Smsmith
18765245Smsmith    debug_called(1);
18865245Smsmith
18951974Smsmith    /*
19051974Smsmith     * Initialise per-controller queues.
19151974Smsmith     */
19265245Smsmith    TAILQ_INIT(&sc->amr_completed);
19351974Smsmith    TAILQ_INIT(&sc->amr_freecmds);
19465245Smsmith    TAILQ_INIT(&sc->amr_cmd_clusters);
19565245Smsmith    TAILQ_INIT(&sc->amr_ready);
19659249Sphk    bioq_init(&sc->amr_bioq);
19751974Smsmith
19865245Smsmith    debug(2, "queue init done");
19965245Smsmith
20065245Smsmith    /*
20151974Smsmith     * Configure for this controller type.
20251974Smsmith     */
20365245Smsmith    if (AMR_IS_QUARTZ(sc)) {
20451974Smsmith	sc->amr_submit_command = amr_quartz_submit_command;
20551974Smsmith	sc->amr_get_work       = amr_quartz_get_work;
206107756Semoore	sc->amr_poll_command   = amr_quartz_poll_command;
207138422Sscottl	sc->amr_poll_command1  = amr_quartz_poll_command1;
20851974Smsmith    } else {
20951974Smsmith	sc->amr_submit_command = amr_std_submit_command;
21051974Smsmith	sc->amr_get_work       = amr_std_get_work;
211107756Semoore	sc->amr_poll_command   = amr_std_poll_command;
21265245Smsmith	amr_std_attach_mailbox(sc);;
21351974Smsmith    }
21451974Smsmith
21565245Smsmith#ifdef AMR_BOARD_INIT
21665245Smsmith    if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc))))
21765245Smsmith	return(ENXIO);
21865245Smsmith#endif
21951974Smsmith
22051974Smsmith    /*
22165245Smsmith     * Quiz controller for features and limits.
22251974Smsmith     */
22365245Smsmith    if (amr_query_controller(sc))
22465245Smsmith	return(ENXIO);
22551974Smsmith
22665245Smsmith    debug(2, "controller query complete");
22751974Smsmith
22851974Smsmith    /*
22965245Smsmith     * Attach our 'real' SCSI channels to CAM.
23051974Smsmith     */
23165245Smsmith    if (amr_cam_attach(sc))
23251974Smsmith	return(ENXIO);
23365245Smsmith    debug(2, "CAM attach done");
23451974Smsmith
23551974Smsmith    /*
23665245Smsmith     * Create the control device.
23751974Smsmith     */
23865245Smsmith    sc->amr_dev_t = make_dev(&amr_cdevsw, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR,
23965245Smsmith			     S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev));
24065245Smsmith    sc->amr_dev_t->si_drv1 = sc;
24151974Smsmith
24251974Smsmith    /*
24365245Smsmith     * Schedule ourselves to bring the controller up once interrupts are
24465245Smsmith     * available.
24551974Smsmith     */
24665245Smsmith    bzero(&sc->amr_ich, sizeof(struct intr_config_hook));
24765245Smsmith    sc->amr_ich.ich_func = amr_startup;
24865245Smsmith    sc->amr_ich.ich_arg = sc;
24965245Smsmith    if (config_intrhook_establish(&sc->amr_ich) != 0) {
25065245Smsmith	device_printf(sc->amr_dev, "can't establish configuration hook\n");
25165245Smsmith	return(ENOMEM);
25265245Smsmith    }
25351974Smsmith
25458883Smsmith    /*
25565245Smsmith     * Print a little information about the controller.
25658883Smsmith     */
25765245Smsmith    amr_describe_controller(sc);
25858883Smsmith
25965245Smsmith    debug(2, "attach complete");
26051974Smsmith    return(0);
26151974Smsmith}
26251974Smsmith
26351974Smsmith/********************************************************************************
26451974Smsmith * Locate disk resources and attach children to them.
26551974Smsmith */
26665245Smsmithstatic void
26765245Smsmithamr_startup(void *arg)
26851974Smsmith{
26965245Smsmith    struct amr_softc	*sc = (struct amr_softc *)arg;
27051974Smsmith    struct amr_logdrive	*dr;
27151974Smsmith    int			i, error;
27251974Smsmith
27365245Smsmith    debug_called(1);
27451974Smsmith
27565245Smsmith    /* pull ourselves off the intrhook chain */
27665245Smsmith    config_intrhook_disestablish(&sc->amr_ich);
27765245Smsmith
27851974Smsmith    /* get up-to-date drive information */
27951974Smsmith    if (amr_query_controller(sc)) {
28065245Smsmith	device_printf(sc->amr_dev, "can't scan controller for drives\n");
28151974Smsmith	return;
28251974Smsmith    }
28351974Smsmith
28451974Smsmith    /* iterate over available drives */
28551974Smsmith    for (i = 0, dr = &sc->amr_drive[0]; (i < AMR_MAXLD) && (dr->al_size != 0xffffffff); i++, dr++) {
28651974Smsmith	/* are we already attached to this drive? */
28751974Smsmith	if (dr->al_disk == 0) {
28851974Smsmith	    /* generate geometry information */
28951974Smsmith	    if (dr->al_size > 0x200000) {	/* extended translation? */
29051974Smsmith		dr->al_heads = 255;
29151974Smsmith		dr->al_sectors = 63;
29251974Smsmith	    } else {
29351974Smsmith		dr->al_heads = 64;
29451974Smsmith		dr->al_sectors = 32;
29551974Smsmith	    }
29651974Smsmith	    dr->al_cylinders = dr->al_size / (dr->al_heads * dr->al_sectors);
29751974Smsmith
29854073Smdodd	    dr->al_disk = device_add_child(sc->amr_dev, NULL, -1);
29951974Smsmith	    if (dr->al_disk == 0)
30051974Smsmith		device_printf(sc->amr_dev, "device_add_child failed\n");
30154073Smdodd	    device_set_ivars(dr->al_disk, dr);
30251974Smsmith	}
30351974Smsmith    }
30451974Smsmith
30551974Smsmith    if ((error = bus_generic_attach(sc->amr_dev)) != 0)
30651974Smsmith	device_printf(sc->amr_dev, "bus_generic_attach returned %d\n", error);
30751974Smsmith
30851974Smsmith    /* mark controller back up */
30951974Smsmith    sc->amr_state &= ~AMR_STATE_SHUTDOWN;
31051974Smsmith
31151974Smsmith    /* interrupts will be enabled before we do anything more */
31251974Smsmith    sc->amr_state |= AMR_STATE_INTEN;
31351974Smsmith
31451974Smsmith    /*
31565245Smsmith     * Start the timeout routine.
31651974Smsmith     */
31765245Smsmith/*    sc->amr_timeout = timeout(amr_periodic, sc, hz);*/
31851974Smsmith
31965245Smsmith    return;
32051974Smsmith}
32151974Smsmith
32265245Smsmith/*******************************************************************************
32365245Smsmith * Free resources associated with a controller instance
32451974Smsmith */
32565245Smsmithvoid
32665245Smsmithamr_free(struct amr_softc *sc)
32751974Smsmith{
32865245Smsmith    struct amr_command_cluster	*acc;
32951974Smsmith
33065245Smsmith    /* detach from CAM */
331107756Semoore    amr_cam_detach(sc);
33251974Smsmith
33365245Smsmith    /* cancel status timeout */
33465245Smsmith    untimeout(amr_periodic, sc, sc->amr_timeout);
33551974Smsmith
33665245Smsmith    /* throw away any command buffers */
33765245Smsmith    while ((acc = TAILQ_FIRST(&sc->amr_cmd_clusters)) != NULL) {
33865245Smsmith	TAILQ_REMOVE(&sc->amr_cmd_clusters, acc, acc_link);
33965245Smsmith	amr_freecmd_cluster(acc);
34051974Smsmith    }
341107756Semoore
342107756Semoore    /* destroy control device */
343130585Sphk    if( sc->amr_dev_t != (struct cdev *)NULL)
344107756Semoore	    destroy_dev(sc->amr_dev_t);
345140340Sscottl
346140340Sscottl    if (mtx_initialized(&sc->amr_io_lock))
347140340Sscottl	mtx_destroy(&sc->amr_io_lock);
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
359140340Sscottl    mtx_lock(&sc->amr_io_lock);
36065245Smsmith    amr_enqueue_bio(sc, bio);
36151974Smsmith    amr_startio(sc);
362140340Sscottl    mtx_unlock(&sc->amr_io_lock);
36351974Smsmith    return(0);
36451974Smsmith}
36551974Smsmith
36651974Smsmith/********************************************************************************
36751974Smsmith * Accept an open operation on the control device.
36851974Smsmith */
369104094Sphkstatic int
370130585Sphkamr_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
37151974Smsmith{
37251974Smsmith    int			unit = minor(dev);
37389055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
37451974Smsmith
37565245Smsmith    debug_called(1);
37665245Smsmith
37751974Smsmith    sc->amr_state |= AMR_STATE_OPEN;
37851974Smsmith    return(0);
37951974Smsmith}
38051974Smsmith
38151974Smsmith/********************************************************************************
38251974Smsmith * Accept the last close on the control device.
38351974Smsmith */
384104094Sphkstatic int
385130585Sphkamr_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
38651974Smsmith{
38751974Smsmith    int			unit = minor(dev);
38889055Smsmith    struct amr_softc	*sc = devclass_get_softc(devclass_find("amr"), unit);
38951974Smsmith
39065245Smsmith    debug_called(1);
39165245Smsmith
39251974Smsmith    sc->amr_state &= ~AMR_STATE_OPEN;
39351974Smsmith    return (0);
39451974Smsmith}
39551974Smsmith
39651974Smsmith/********************************************************************************
39751974Smsmith * Handle controller-specific control operations.
39851974Smsmith */
399104094Sphkstatic int
400130585Sphkamr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
40151974Smsmith{
40265245Smsmith    struct amr_softc		*sc = (struct amr_softc *)dev->si_drv1;
403133870Sambrisko    union {
404133870Sambrisko	void			*_p;
405133870Sambrisko	struct amr_user_ioctl	*au;
406133870Sambrisko#ifdef AMR_IO_COMMAND32
407133870Sambrisko	struct amr_user_ioctl32	*au32;
408133870Sambrisko#endif
409133870Sambrisko	int			*result;
410133870Sambrisko    } arg;
41165245Smsmith    struct amr_command		*ac;
41265245Smsmith    struct amr_mailbox_ioctl	*mbi;
413133870Sambrisko    void			*dp, *au_buffer;
414133870Sambrisko    unsigned long		au_length;
415133870Sambrisko    unsigned char		*au_cmd;
416133870Sambrisko    int				*au_statusp, au_direction;
41765245Smsmith    int				error;
418143121Sscottl    struct amr_passthrough	*ap;	/* 60 bytes */
41965245Smsmith
42065245Smsmith    debug_called(1);
42165245Smsmith
422133870Sambrisko    arg._p = (void *)addr;
423133870Sambrisko
42451974Smsmith    switch(cmd) {
42565245Smsmith
42665245Smsmith    case AMR_IO_VERSION:
42765245Smsmith	debug(1, "AMR_IO_VERSION");
428133870Sambrisko	*arg.result = AMR_IO_VERSION_NUMBER;
429133870Sambrisko	return(0);
430133870Sambrisko
431133870Sambrisko#ifdef AMR_IO_COMMAND32
432133870Sambrisko    /*
433133870Sambrisko     * Accept ioctl-s from 32-bit binaries on non-32-bit
434133870Sambrisko     * platforms, such as AMD. LSI's MEGAMGR utility is
435133870Sambrisko     * the only example known today...	-mi
436133870Sambrisko     */
437133870Sambrisko    case AMR_IO_COMMAND32:
438133870Sambrisko	debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]);
439133870Sambrisko	au_cmd = arg.au32->au_cmd;
440133870Sambrisko	au_buffer = (void *)(u_int64_t)arg.au32->au_buffer;
441133870Sambrisko	au_length = arg.au32->au_length;
442133870Sambrisko	au_direction = arg.au32->au_direction;
443133870Sambrisko	au_statusp = &arg.au32->au_status;
44465245Smsmith	break;
445133870Sambrisko#endif
44665245Smsmith
44765245Smsmith    case AMR_IO_COMMAND:
448133870Sambrisko	debug(1, "AMR_IO_COMMAND  0x%x", arg.au->au_cmd[0]);
449133870Sambrisko	au_cmd = arg.au->au_cmd;
450133870Sambrisko	au_buffer = (void *)arg.au->au_buffer;
451133870Sambrisko	au_length = arg.au->au_length;
452133870Sambrisko	au_direction = arg.au->au_direction;
453133870Sambrisko	au_statusp = &arg.au->au_status;
454133870Sambrisko	break;
45565245Smsmith
456133870Sambrisko    default:
457133870Sambrisko	debug(1, "unknown ioctl 0x%lx", cmd);
458133870Sambrisko	return(ENOIOCTL);
459133870Sambrisko    }
46065245Smsmith
461133870Sambrisko    error = 0;
462133870Sambrisko    dp = NULL;
463133870Sambrisko    ac = NULL;
464143121Sscottl    ap = NULL;
46565245Smsmith
466140688Sscottl    /* Logical Drive not supported by the driver */
467140688Sscottl    if (au_cmd[0] == 0xa4 && au_cmd[1] == 0x1c)
468140688Sscottl	return (ENOIOCTL);
469140688Sscottl
470133870Sambrisko    /* handle inbound data buffer */
471140688Sscottl    if (au_length != 0 && au_cmd[0] != 0x06) {
472143488Sscottl	dp = malloc(au_length, M_DEVBUF, M_WAITOK|M_ZERO);
47365245Smsmith
474140340Sscottl	if ((error = copyin(au_buffer, dp, au_length)) != 0) {
475140340Sscottl	    free(dp, M_DEVBUF);
476140340Sscottl	    return (error);
477140340Sscottl	}
478133870Sambrisko	debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp);
479133870Sambrisko    }
48065245Smsmith
481143488Sscottl    /* Allocate this now before the mutex gets held */
482143488Sscottl    if (au_cmd[0] == AMR_CMD_PASS)
483143488Sscottl	ap = malloc(sizeof(struct amr_passthrough), M_DEVBUF, M_WAITOK|M_ZERO);
484143488Sscottl
485140340Sscottl    mtx_lock(&sc->amr_io_lock);
486133870Sambrisko    if ((ac = amr_alloccmd(sc)) == NULL) {
487133870Sambrisko	error = ENOMEM;
488133870Sambrisko	goto out;
489133870Sambrisko    }
49065245Smsmith
491133870Sambrisko    /* handle SCSI passthrough command */
492133870Sambrisko    if (au_cmd[0] == AMR_CMD_PASS) {
493140340Sscottl        int len;
49465245Smsmith
495133870Sambrisko	/* copy cdb */
496140340Sscottl        len = au_cmd[2];
497143121Sscottl	ap->ap_cdb_length = len;
498143121Sscottl	bcopy(au_cmd + 3, ap->ap_cdb, len);
49965245Smsmith
500133870Sambrisko	/* build passthrough */
501143121Sscottl	ap->ap_timeout		= au_cmd[len + 3] & 0x07;
502143121Sscottl	ap->ap_ars		= (au_cmd[len + 3] & 0x08) ? 1 : 0;
503143121Sscottl	ap->ap_islogical		= (au_cmd[len + 3] & 0x80) ? 1 : 0;
504143121Sscottl	ap->ap_logical_drive_no	= au_cmd[len + 4];
505143121Sscottl	ap->ap_channel		= au_cmd[len + 5];
506143121Sscottl	ap->ap_scsi_id 		= au_cmd[len + 6];
507143121Sscottl	ap->ap_request_sense_length	= 14;
508143121Sscottl	ap->ap_data_transfer_length	= au_length;
509133870Sambrisko	/* XXX what about the request-sense area? does the caller want it? */
51065245Smsmith
511133870Sambrisko	/* build command */
512143121Sscottl	ac->ac_data = ap;
513140340Sscottl	ac->ac_length = sizeof(struct amr_passthrough);
514133870Sambrisko	ac->ac_flags |= AMR_CMD_DATAOUT;
515133870Sambrisko	ac->ac_ccb_data = dp;
516133870Sambrisko	ac->ac_ccb_length = au_length;
517133870Sambrisko	if (au_direction & AMR_IO_READ)
518133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAIN;
519133870Sambrisko	if (au_direction & AMR_IO_WRITE)
520133870Sambrisko	    ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
52165245Smsmith
522133870Sambrisko	ac->ac_mailbox.mb_command = AMR_CMD_PASS;
52365245Smsmith
524133870Sambrisko    } else {
525133870Sambrisko	/* direct command to controller */
526133870Sambrisko	mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
527105419Semoore
528133870Sambrisko	/* copy pertinent mailbox items */
529133870Sambrisko	mbi->mb_command = au_cmd[0];
530133870Sambrisko	mbi->mb_channel = au_cmd[1];
531133870Sambrisko	mbi->mb_param = au_cmd[2];
532133870Sambrisko	mbi->mb_pad[0] = au_cmd[3];
533133870Sambrisko	mbi->mb_drive = au_cmd[4];
534133870Sambrisko
535133870Sambrisko	/* build the command */
536133870Sambrisko	ac->ac_data = dp;
537133870Sambrisko	ac->ac_length = au_length;
538133870Sambrisko	if (au_direction & AMR_IO_READ)
539133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAIN;
540133870Sambrisko	if (au_direction & AMR_IO_WRITE)
541133870Sambrisko	    ac->ac_flags |= AMR_CMD_DATAOUT;
54251974Smsmith    }
54351974Smsmith
544133870Sambrisko    /* run the command */
545133870Sambrisko    if ((error = amr_wait_command(ac)) != 0)
546133870Sambrisko	goto out;
547133870Sambrisko
548133870Sambrisko    /* copy out data and set status */
549140340Sscottl    if (au_length != 0) {
550140340Sscottl	mtx_unlock(&sc->amr_io_lock);
551133870Sambrisko	error = copyout(dp, au_buffer, au_length);
552140340Sscottl	mtx_lock(&sc->amr_io_lock);
553140340Sscottl    }
554133870Sambrisko    debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
55565245Smsmith    if (dp != NULL)
556133870Sambrisko	debug(2, "%16d", (int)dp);
557133870Sambrisko    *au_statusp = ac->ac_status;
558133870Sambrisko
559133870Sambriskoout:
560140340Sscottl    /*
561140340Sscottl     * At this point, we know that there is a lock held and that these
562140340Sscottl     * objects have been allocated.
563140340Sscottl     */
564143488Sscottl    if (ac != NULL)
565143488Sscottl	amr_releasecmd(ac);
566140340Sscottl    mtx_unlock(&sc->amr_io_lock);
567143488Sscottl    if (dp != NULL)
568143488Sscottl	free(dp, M_DEVBUF);
569143488Sscottl    if (ap != NULL)
570143488Sscottl	free(ap, M_DEVBUF);
57165245Smsmith    return(error);
57251974Smsmith}
57351974Smsmith
57451974Smsmith/********************************************************************************
57551974Smsmith ********************************************************************************
57658883Smsmith                                                                Status Monitoring
57758883Smsmith ********************************************************************************
57858883Smsmith ********************************************************************************/
57958883Smsmith
58058883Smsmith/********************************************************************************
58158883Smsmith * Perform a periodic check of the controller status
58258883Smsmith */
58358883Smsmithstatic void
58458883Smsmithamr_periodic(void *data)
58558883Smsmith{
58658883Smsmith    struct amr_softc	*sc = (struct amr_softc *)data;
58758883Smsmith
58865245Smsmith    debug_called(2);
58958883Smsmith
59065245Smsmith    /* XXX perform periodic status checks here */
59158883Smsmith
59265245Smsmith    /* compensate for missed interrupts */
59365245Smsmith    amr_done(sc);
59465245Smsmith
59558883Smsmith    /* reschedule */
59658883Smsmith    sc->amr_timeout = timeout(amr_periodic, sc, hz);
59758883Smsmith}
59858883Smsmith
59958883Smsmith/********************************************************************************
60058883Smsmith ********************************************************************************
60151974Smsmith                                                                 Command Wrappers
60251974Smsmith ********************************************************************************
60351974Smsmith ********************************************************************************/
60451974Smsmith
60551974Smsmith/********************************************************************************
60651974Smsmith * Interrogate the controller for the operational parameters we require.
60751974Smsmith */
60851974Smsmithstatic int
60951974Smsmithamr_query_controller(struct amr_softc *sc)
61051974Smsmith{
61165245Smsmith    struct amr_enquiry3	*aex;
61265245Smsmith    struct amr_prodinfo	*ap;
61365245Smsmith    struct amr_enquiry	*ae;
61465245Smsmith    int			ldrv;
61551974Smsmith
616140340Sscottl    mtx_lock(&sc->amr_io_lock);
617140340Sscottl
61865245Smsmith    /*
61965245Smsmith     * If we haven't found the real limit yet, let us have a couple of commands in
62065245Smsmith     * order to be able to probe.
62165245Smsmith     */
62265245Smsmith    if (sc->amr_maxio == 0)
62365245Smsmith	sc->amr_maxio = 2;
62451974Smsmith
625106225Semoore    /*
626106225Semoore     * Greater than 10 byte cdb support
627106225Semoore     */
628106225Semoore    sc->support_ext_cdb = amr_support_ext_cdb(sc);
629106225Semoore
630106225Semoore    if(sc->support_ext_cdb) {
631106225Semoore	debug(2,"supports extended CDBs.");
632106225Semoore    }
633106225Semoore
63465245Smsmith    /*
63565245Smsmith     * Try to issue an ENQUIRY3 command
63665245Smsmith     */
63765245Smsmith    if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
63865245Smsmith			   AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
63951974Smsmith
64065245Smsmith	/*
64165245Smsmith	 * Fetch current state of logical drives.
64265245Smsmith	 */
64365245Smsmith	for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
64465245Smsmith	    sc->amr_drive[ldrv].al_size       = aex->ae_drivesize[ldrv];
64565245Smsmith	    sc->amr_drive[ldrv].al_state      = aex->ae_drivestate[ldrv];
64665245Smsmith	    sc->amr_drive[ldrv].al_properties = aex->ae_driveprop[ldrv];
64765245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
64865245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
64951974Smsmith	}
65065245Smsmith	free(aex, M_DEVBUF);
65158883Smsmith
65265245Smsmith	/*
65365245Smsmith	 * Get product info for channel count.
65458883Smsmith	 */
65565245Smsmith	if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
65665245Smsmith	    device_printf(sc->amr_dev, "can't obtain product data from controller\n");
657140340Sscottl	    mtx_unlock(&sc->amr_io_lock);
65865245Smsmith	    return(1);
65965245Smsmith	}
66065245Smsmith	sc->amr_maxdrives = 40;
66165245Smsmith	sc->amr_maxchan = ap->ap_nschan;
66265245Smsmith	sc->amr_maxio = ap->ap_maxio;
66365245Smsmith	sc->amr_type |= AMR_TYPE_40LD;
66465245Smsmith	free(ap, M_DEVBUF);
66558883Smsmith
66665245Smsmith    } else {
66765245Smsmith
66865245Smsmith	/* failed, try the 8LD ENQUIRY commands */
66965245Smsmith	if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) {
67065245Smsmith	    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) {
67165245Smsmith		device_printf(sc->amr_dev, "can't obtain configuration data from controller\n");
672140340Sscottl		mtx_unlock(&sc->amr_io_lock);
67365245Smsmith		return(1);
67465245Smsmith	    }
67565245Smsmith	    ae->ae_signature = 0;
67651974Smsmith	}
67765245Smsmith
67858883Smsmith	/*
67965245Smsmith	 * Fetch current state of logical drives.
68058883Smsmith	 */
68165245Smsmith	for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
68265245Smsmith	    sc->amr_drive[ldrv].al_size       = ae->ae_ldrv.al_size[ldrv];
68365245Smsmith	    sc->amr_drive[ldrv].al_state      = ae->ae_ldrv.al_state[ldrv];
68465245Smsmith	    sc->amr_drive[ldrv].al_properties = ae->ae_ldrv.al_properties[ldrv];
68565245Smsmith	    debug(2, "  drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
68665245Smsmith		  sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
68751974Smsmith	}
68865245Smsmith
68965245Smsmith	sc->amr_maxdrives = 8;
69065245Smsmith	sc->amr_maxchan = ae->ae_adapter.aa_channels;
69165245Smsmith	sc->amr_maxio = ae->ae_adapter.aa_maxio;
69265245Smsmith	free(ae, M_DEVBUF);
69351974Smsmith    }
69465245Smsmith
69565245Smsmith    /*
69665245Smsmith     * Mark remaining drives as unused.
69765245Smsmith     */
69865245Smsmith    for (; ldrv < AMR_MAXLD; ldrv++)
69965245Smsmith	sc->amr_drive[ldrv].al_size = 0xffffffff;
70065245Smsmith
70165245Smsmith    /*
70265245Smsmith     * Cap the maximum number of outstanding I/Os.  AMI's Linux driver doesn't trust
70365245Smsmith     * the controller's reported value, and lockups have been seen when we do.
70465245Smsmith     */
70565245Smsmith    sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD);
70665245Smsmith
707140340Sscottl    mtx_unlock(&sc->amr_io_lock);
70851974Smsmith    return(0);
70951974Smsmith}
71051974Smsmith
71151974Smsmith/********************************************************************************
71251974Smsmith * Run a generic enquiry-style command.
71351974Smsmith */
71451974Smsmithstatic void *
71551974Smsmithamr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
71651974Smsmith{
71751974Smsmith    struct amr_command	*ac;
71851974Smsmith    void		*result;
71951974Smsmith    u_int8_t		*mbox;
72051974Smsmith    int			error;
72151974Smsmith
72265245Smsmith    debug_called(1);
72351974Smsmith
72451974Smsmith    error = 1;
72551974Smsmith    result = NULL;
72651974Smsmith
72751974Smsmith    /* get ourselves a command buffer */
72851974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
72951974Smsmith	goto out;
73051974Smsmith    /* allocate the response structure */
731138422Sscottl    if ((result = malloc(bufsize, M_DEVBUF, M_ZERO|M_NOWAIT)) == NULL)
73251974Smsmith	goto out;
73365245Smsmith    /* set command flags */
734138422Sscottl
735135236Sscottl    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN;
73651974Smsmith
73765245Smsmith    /* point the command at our data */
73851974Smsmith    ac->ac_data = result;
73951974Smsmith    ac->ac_length = bufsize;
74051974Smsmith
74151974Smsmith    /* build the command proper */
74251974Smsmith    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
74351974Smsmith    mbox[0] = cmd;
74451974Smsmith    mbox[2] = cmdsub;
74551974Smsmith    mbox[3] = cmdqual;
74651974Smsmith
74758883Smsmith    /* can't assume that interrupts are going to work here, so play it safe */
748107756Semoore    if (sc->amr_poll_command(ac))
74951974Smsmith	goto out;
75051974Smsmith    error = ac->ac_status;
75151974Smsmith
75251974Smsmith out:
75351974Smsmith    if (ac != NULL)
75451974Smsmith	amr_releasecmd(ac);
75551974Smsmith    if ((error != 0) && (result != NULL)) {
75651974Smsmith	free(result, M_DEVBUF);
75751974Smsmith	result = NULL;
75851974Smsmith    }
75951974Smsmith    return(result);
76051974Smsmith}
76151974Smsmith
76251974Smsmith/********************************************************************************
76351974Smsmith * Flush the controller's internal cache, return status.
76451974Smsmith */
76565245Smsmithint
76651974Smsmithamr_flush(struct amr_softc *sc)
76751974Smsmith{
76851974Smsmith    struct amr_command	*ac;
76951974Smsmith    int			error;
77051974Smsmith
77151974Smsmith    /* get ourselves a command buffer */
77251974Smsmith    error = 1;
773140340Sscottl    mtx_lock(&sc->amr_io_lock);
77451974Smsmith    if ((ac = amr_alloccmd(sc)) == NULL)
77551974Smsmith	goto out;
77665245Smsmith    /* set command flags */
77751974Smsmith    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
77851974Smsmith
77951974Smsmith    /* build the command proper */
78051974Smsmith    ac->ac_mailbox.mb_command = AMR_CMD_FLUSH;
78151974Smsmith
78258883Smsmith    /* we have to poll, as the system may be going down or otherwise damaged */
783107756Semoore    if (sc->amr_poll_command(ac))
78451974Smsmith	goto out;
78551974Smsmith    error = ac->ac_status;
78651974Smsmith
78751974Smsmith out:
78851974Smsmith    if (ac != NULL)
78951974Smsmith	amr_releasecmd(ac);
790140340Sscottl    mtx_unlock(&sc->amr_io_lock);
79151974Smsmith    return(error);
79251974Smsmith}
79351974Smsmith
79451974Smsmith/********************************************************************************
795106225Semoore * Detect extented cdb >> greater than 10 byte cdb support
796106225Semoore * returns '1' means this support exist
797106225Semoore * returns '0' means this support doesn't exist
798106225Semoore */
799106225Semoorestatic int
800106225Semooreamr_support_ext_cdb(struct amr_softc *sc)
801106225Semoore{
802106225Semoore    struct amr_command	*ac;
803106225Semoore    u_int8_t		*mbox;
804106225Semoore    int			error;
805106225Semoore
806106225Semoore    /* get ourselves a command buffer */
807106225Semoore    error = 0;
808106225Semoore    if ((ac = amr_alloccmd(sc)) == NULL)
809106225Semoore	goto out;
810106225Semoore    /* set command flags */
811106225Semoore    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
812106225Semoore
813106225Semoore    /* build the command proper */
814106225Semoore    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
815106225Semoore    mbox[0] = 0xA4;
816106225Semoore    mbox[2] = 0x16;
817106225Semoore
818106225Semoore
819106225Semoore    /* we have to poll, as the system may be going down or otherwise damaged */
820107756Semoore    if (sc->amr_poll_command(ac))
821106225Semoore	goto out;
822106225Semoore    if( ac->ac_status == AMR_STATUS_SUCCESS ) {
823106225Semoore	    error = 1;
824106225Semoore    }
825106225Semoore
826106225Semooreout:
827106225Semoore    if (ac != NULL)
828106225Semoore	amr_releasecmd(ac);
829106225Semoore    return(error);
830106225Semoore}
831106225Semoore
832106225Semoore/********************************************************************************
83365245Smsmith * Try to find I/O work for the controller from one or more of the work queues.
83451974Smsmith *
83565245Smsmith * We make the assumption that if the controller is not ready to take a command
83665245Smsmith * at some given time, it will generate an interrupt at some later time when
83765245Smsmith * it is.
83851974Smsmith */
83965245Smsmithvoid
84051974Smsmithamr_startio(struct amr_softc *sc)
84151974Smsmith{
84251974Smsmith    struct amr_command	*ac;
84351974Smsmith
84451974Smsmith    /* spin until something prevents us from doing any work */
84551974Smsmith    for (;;) {
84651974Smsmith
847138422Sscottl	/* Don't bother to queue commands no bounce buffers are available. */
848138422Sscottl	if (sc->amr_state & AMR_STATE_QUEUE_FRZN)
849138422Sscottl	    break;
850138422Sscottl
85165245Smsmith	/* try to get a ready command */
85265245Smsmith	ac = amr_dequeue_ready(sc);
85351974Smsmith
85465245Smsmith	/* if that failed, build a command from a bio */
85565245Smsmith	if (ac == NULL)
85665245Smsmith	    (void)amr_bio_command(sc, &ac);
85751974Smsmith
85865245Smsmith	/* if that failed, build a command from a ccb */
85965245Smsmith	if (ac == NULL)
86065245Smsmith	    (void)amr_cam_command(sc, &ac);
861105419Semoore
86265245Smsmith	/* if we don't have anything to do, give up */
86365245Smsmith	if (ac == NULL)
86465245Smsmith	    break;
86551974Smsmith
86665245Smsmith	/* try to give the command to the controller; if this fails save it for later and give up */
86765245Smsmith	if (amr_start(ac)) {
86865245Smsmith	    debug(2, "controller busy, command deferred");
86965245Smsmith	    amr_requeue_ready(ac);	/* XXX schedule retry very soon? */
87065245Smsmith	    break;
87151974Smsmith	}
87251974Smsmith    }
87351974Smsmith}
87451974Smsmith
87551974Smsmith/********************************************************************************
87651974Smsmith * Handle completion of an I/O command.
87751974Smsmith */
87851974Smsmithstatic void
87951974Smsmithamr_completeio(struct amr_command *ac)
88051974Smsmith{
881148499Sps    struct amrd_softc	*sc = ac->ac_bio->bio_disk->d_drv1;
882140340Sscottl
88351974Smsmith    if (ac->ac_status != AMR_STATUS_SUCCESS) {	/* could be more verbose here? */
88465245Smsmith	ac->ac_bio->bio_error = EIO;
88565245Smsmith	ac->ac_bio->bio_flags |= BIO_ERROR;
88651974Smsmith
887148499Sps	device_printf(sc->amrd_dev, "I/O error - 0x%x\n", ac->ac_status);
88865245Smsmith/*	amr_printcommand(ac);*/
88951974Smsmith    }
89065245Smsmith    amrd_intr(ac->ac_bio);
89165245Smsmith    amr_releasecmd(ac);
89251974Smsmith}
89351974Smsmith
89451974Smsmith/********************************************************************************
89551974Smsmith ********************************************************************************
89651974Smsmith                                                               Command Processing
89751974Smsmith ********************************************************************************
89851974Smsmith ********************************************************************************/
89951974Smsmith
90051974Smsmith/********************************************************************************
90165245Smsmith * Convert a bio off the top of the bio queue into a command.
90265245Smsmith */
90365245Smsmithstatic int
90465245Smsmithamr_bio_command(struct amr_softc *sc, struct amr_command **acp)
90565245Smsmith{
90665245Smsmith    struct amr_command	*ac;
90765245Smsmith    struct amrd_softc	*amrd;
90865245Smsmith    struct bio		*bio;
90965245Smsmith    int			error;
91065245Smsmith    int			blkcount;
91165245Smsmith    int			driveno;
91265245Smsmith    int			cmd;
91365245Smsmith
91465245Smsmith    ac = NULL;
91565245Smsmith    error = 0;
91665245Smsmith
917140340Sscottl    /* get a command */
918140340Sscottl    if ((ac = amr_alloccmd(sc)) == NULL)
919140340Sscottl	return (ENOMEM);
920140340Sscottl
92165245Smsmith    /* get a bio to work on */
922140340Sscottl    if ((bio = amr_dequeue_bio(sc)) == NULL) {
923140340Sscottl	amr_releasecmd(ac);
924140340Sscottl	return (0);
925140340Sscottl    }
92665245Smsmith
92765245Smsmith    /* connect the bio to the command */
92865245Smsmith    ac->ac_complete = amr_completeio;
92965245Smsmith    ac->ac_bio = bio;
93065245Smsmith    ac->ac_data = bio->bio_data;
93165245Smsmith    ac->ac_length = bio->bio_bcount;
93265245Smsmith    if (BIO_IS_READ(bio)) {
93365245Smsmith	ac->ac_flags |= AMR_CMD_DATAIN;
93465245Smsmith	cmd = AMR_CMD_LREAD;
93565245Smsmith    } else {
93665245Smsmith	ac->ac_flags |= AMR_CMD_DATAOUT;
93765245Smsmith	cmd = AMR_CMD_LWRITE;
93865245Smsmith    }
939111441Sphk    amrd = (struct amrd_softc *)bio->bio_disk->d_drv1;
94065245Smsmith    driveno = amrd->amrd_drive - sc->amr_drive;
94165245Smsmith    blkcount = (bio->bio_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE;
94265245Smsmith
94365245Smsmith    ac->ac_mailbox.mb_command = cmd;
94465245Smsmith    ac->ac_mailbox.mb_blkcount = blkcount;
94565245Smsmith    ac->ac_mailbox.mb_lba = bio->bio_pblkno;
94665245Smsmith    ac->ac_mailbox.mb_drive = driveno;
94765245Smsmith    /* we fill in the s/g related data when the command is mapped */
94865245Smsmith
94965245Smsmith    if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size)
95092610Sbde	device_printf(sc->amr_dev, "I/O beyond end of unit (%lld,%d > %lu)\n",
95192610Sbde		      (long long)bio->bio_pblkno, blkcount,
95292610Sbde		      (u_long)sc->amr_drive[driveno].al_size);
95365245Smsmith
95465245Smsmith    *acp = ac;
95565245Smsmith    return(error);
95665245Smsmith}
95765245Smsmith
95865245Smsmith/********************************************************************************
95951974Smsmith * Take a command, submit it to the controller and sleep until it completes
96051974Smsmith * or fails.  Interrupts must be enabled, returns nonzero on error.
96151974Smsmith */
96251974Smsmithstatic int
96351974Smsmithamr_wait_command(struct amr_command *ac)
96451974Smsmith{
965148498Sps    int			error = 0;
96651974Smsmith
96765245Smsmith    debug_called(1);
96851974Smsmith
96951974Smsmith    ac->ac_complete = NULL;
97065245Smsmith    ac->ac_flags |= AMR_CMD_SLEEP;
97151974Smsmith    if ((error = amr_start(ac)) != 0)
97251974Smsmith	return(error);
97351974Smsmith
974148498Sps    while ((ac->ac_flags & AMR_CMD_BUSY) && (error != EWOULDBLOCK)) {
975148498Sps	error = msleep(ac, &ac->ac_sc->amr_io_lock, PRIBIO, "amrwcmd", 0);
97651974Smsmith    }
977148498Sps    return(error);
97851974Smsmith}
97951974Smsmith
98051974Smsmith/********************************************************************************
98151974Smsmith * Take a command, submit it to the controller and busy-wait for it to return.
98251974Smsmith * Returns nonzero on error.  Can be safely called with interrupts enabled.
98351974Smsmith */
98451974Smsmithstatic int
985107756Semooreamr_std_poll_command(struct amr_command *ac)
98651974Smsmith{
98751974Smsmith    struct amr_softc	*sc = ac->ac_sc;
98865245Smsmith    int			error, count;
98951974Smsmith
99065245Smsmith    debug_called(2);
99151974Smsmith
99251974Smsmith    ac->ac_complete = NULL;
99351974Smsmith    if ((error = amr_start(ac)) != 0)
99451974Smsmith	return(error);
99551974Smsmith
99651974Smsmith    count = 0;
99751974Smsmith    do {
99851974Smsmith	/*
99951974Smsmith	 * Poll for completion, although the interrupt handler may beat us to it.
100051974Smsmith	 * Note that the timeout here is somewhat arbitrary.
100151974Smsmith	 */
100251974Smsmith	amr_done(sc);
100365245Smsmith	DELAY(1000);
100465245Smsmith    } while ((ac->ac_flags & AMR_CMD_BUSY) && (count++ < 1000));
100565245Smsmith    if (!(ac->ac_flags & AMR_CMD_BUSY)) {
100651974Smsmith	error = 0;
100751974Smsmith    } else {
100865245Smsmith	/* XXX the slot is now marked permanently busy */
100951974Smsmith	error = EIO;
101065245Smsmith	device_printf(sc->amr_dev, "polled command timeout\n");
101151974Smsmith    }
101251974Smsmith    return(error);
101351974Smsmith}
101451974Smsmith
1015138422Sscottlstatic void
1016138422Sscottlamr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
1017138422Sscottl{
1018138422Sscottl    struct amr_command *ac = arg;
1019138422Sscottl    struct amr_softc *sc = ac->ac_sc;
1020138422Sscottl
1021138422Sscottl    amr_setup_dmamap(arg, segs, nsegs, err);
1022147536Sps    if (ac->ac_flags & AMR_CMD_DATAIN) {
1023147536Sps	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
1024147536Sps	    BUS_DMASYNC_PREREAD);
1025147536Sps    }
1026147536Sps    if (ac->ac_flags & AMR_CMD_DATAOUT) {
1027147536Sps	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
1028147536Sps	    BUS_DMASYNC_PREWRITE);
1029147536Sps    }
1030138422Sscottl    sc->amr_poll_command1(sc, ac);
1031138422Sscottl}
1032138422Sscottl
103351974Smsmith/********************************************************************************
1034107756Semoore * Take a command, submit it to the controller and busy-wait for it to return.
1035107756Semoore * Returns nonzero on error.  Can be safely called with interrupts enabled.
1036107756Semoore */
1037107756Semoorestatic int
1038107756Semooreamr_quartz_poll_command(struct amr_command *ac)
1039107756Semoore{
1040107756Semoore    struct amr_softc	*sc = ac->ac_sc;
1041138422Sscottl    int			s, error;
1042107756Semoore
1043107756Semoore    debug_called(2);
1044107756Semoore
1045138422Sscottl    s = splbio();
1046138422Sscottl    error = 0;
1047138422Sscottl
1048107756Semoore    /* now we have a slot, we can map the command (unmapped in amr_complete) */
1049138422Sscottl    if (ac->ac_data != 0) {
1050138422Sscottl	if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1051138422Sscottl	    ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) {
1052138422Sscottl	    error = 1;
1053138422Sscottl	}
1054138422Sscottl    } else {
1055138422Sscottl	error = amr_quartz_poll_command1(sc, ac);
1056138422Sscottl    }
1057107756Semoore
1058138422Sscottl    splx(s);
1059138422Sscottl    return (error);
1060138422Sscottl}
1061107756Semoore
1062138422Sscottlstatic int
1063138422Sscottlamr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac)
1064138422Sscottl{
1065138422Sscottl    int count, error;
1066138422Sscottl
1067140688Sscottl    if ((sc->amr_state & AMR_STATE_INTEN) == 0) {
1068120988Sps	count=0;
1069120988Sps	while (sc->amr_busyslots) {
1070140340Sscottl	    msleep(sc, &sc->amr_io_lock, PRIBIO | PCATCH, "amrpoll", hz);
1071120988Sps	    if(count++>10) {
1072120988Sps		break;
1073120988Sps	    }
1074109031Semoore	}
1075109031Semoore
1076120988Sps	if(sc->amr_busyslots) {
1077120988Sps	    device_printf(sc->amr_dev, "adapter is busy\n");
1078138422Sscottl	    if (ac->ac_data != NULL)
1079138422Sscottl		bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
1080120988Sps    	    ac->ac_status=0;
1081120988Sps	    return(1);
1082120988Sps	}
1083107756Semoore    }
1084107756Semoore
1085107756Semoore    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
1086107756Semoore
1087107756Semoore    /* clear the poll/ack fields in the mailbox */
1088107756Semoore    sc->amr_mailbox->mb_ident = 0xFE;
1089107756Semoore    sc->amr_mailbox->mb_nstatus = 0xFF;
1090107756Semoore    sc->amr_mailbox->mb_status = 0xFF;
1091107756Semoore    sc->amr_mailbox->mb_poll = 0;
1092107756Semoore    sc->amr_mailbox->mb_ack = 0;
1093109031Semoore    sc->amr_mailbox->mb_busy = 1;
1094107756Semoore
1095107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
1096107756Semoore
1097107756Semoore    while(sc->amr_mailbox->mb_nstatus == 0xFF);
1098107756Semoore    while(sc->amr_mailbox->mb_status == 0xFF);
1099107827Semoore    ac->ac_status=sc->amr_mailbox->mb_status;
1100107827Semoore    error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0;
1101107756Semoore    while(sc->amr_mailbox->mb_poll != 0x77);
1102107756Semoore    sc->amr_mailbox->mb_poll = 0;
1103107756Semoore    sc->amr_mailbox->mb_ack = 0x77;
1104107756Semoore
1105107756Semoore    /* acknowledge that we have the commands */
1106107756Semoore    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
1107109031Semoore    while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK);
1108107756Semoore
1109107756Semoore    /* unmap the command's data buffer */
1110147536Sps    if (ac->ac_flags & AMR_CMD_DATAIN) {
1111147536Sps	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
1112147536Sps	    BUS_DMASYNC_POSTREAD);
1113147536Sps    }
1114147536Sps    if (ac->ac_flags & AMR_CMD_DATAOUT) {
1115147536Sps	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
1116147536Sps	    BUS_DMASYNC_POSTWRITE);
1117147536Sps    }
1118138422Sscottl    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
1119107756Semoore
1120107827Semoore    return(error);
1121107756Semoore}
1122107756Semoore
1123107756Semoore/********************************************************************************
112465245Smsmith * Get a free command slot for a command if it doesn't already have one.
112565245Smsmith *
112665245Smsmith * May be safely called multiple times for a given command.
112751974Smsmith */
112851974Smsmithstatic int
112951974Smsmithamr_getslot(struct amr_command *ac)
113051974Smsmith{
113151974Smsmith    struct amr_softc	*sc = ac->ac_sc;
1132140340Sscottl    int slot;
113351974Smsmith
113465245Smsmith    debug_called(3);
113565245Smsmith
1136140340Sscottl    slot = ac->ac_slot;
1137140340Sscottl    if (sc->amr_busycmd[slot] != NULL)
1138140340Sscottl	panic("amr: slot %d busy?\n", slot);
113965245Smsmith
1140140340Sscottl    sc->amr_busycmd[slot] = ac;
1141140340Sscottl    sc->amr_busyslots++;
114251974Smsmith
1143140340Sscottl    return (0);
114451974Smsmith}
114551974Smsmith
114651974Smsmith/********************************************************************************
114765245Smsmith * Map/unmap (ac)'s data in the controller's addressable space as required.
114865245Smsmith *
114965245Smsmith * These functions may be safely called multiple times on a given command.
115051974Smsmith */
115151974Smsmithstatic void
115251974Smsmithamr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
115351974Smsmith{
115451974Smsmith    struct amr_command	*ac = (struct amr_command *)arg;
115551974Smsmith    struct amr_softc	*sc = ac->ac_sc;
115651974Smsmith    struct amr_sgentry	*sg;
115751974Smsmith    int			i;
115869319Smsmith    u_int8_t		*sgc;
115951974Smsmith
116065245Smsmith    debug_called(3);
116151974Smsmith
116251974Smsmith    /* get base address of s/g table */
116351974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
116451974Smsmith
116565245Smsmith    /* save data physical address */
116651974Smsmith    ac->ac_dataphys = segs[0].ds_addr;
116751974Smsmith
116869319Smsmith    /* for AMR_CMD_CONFIG the s/g count goes elsewhere */
116969319Smsmith    if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) {
117069319Smsmith	sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
117169319Smsmith    } else {
117269319Smsmith	sgc = &ac->ac_mailbox.mb_nsgelem;
117369319Smsmith    }
117469319Smsmith
117565245Smsmith    /* decide whether we need to populate the s/g table */
117665245Smsmith    if (nsegments < 2) {
117769319Smsmith	*sgc = 0;
1178105419Semoore	ac->ac_mailbox.mb_nsgelem = 0;
117965245Smsmith	ac->ac_mailbox.mb_physaddr = ac->ac_dataphys;
118065245Smsmith    } else {
1181105419Semoore        ac->ac_mailbox.mb_nsgelem = nsegments;
118269319Smsmith	*sgc = nsegments;
1183138422Sscottl	ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr +
1184138422Sscottl	    (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
118565245Smsmith	for (i = 0; i < nsegments; i++, sg++) {
118665245Smsmith	    sg->sg_addr = segs[i].ds_addr;
118765245Smsmith	    sg->sg_count = segs[i].ds_len;
118865245Smsmith	}
118965245Smsmith    }
1190138422Sscottl
119165245Smsmith}
119265245Smsmith
119365245Smsmithstatic void
119465245Smsmithamr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
119565245Smsmith{
1196105419Semoore    struct amr_command          *ac = (struct amr_command *)arg;
1197105419Semoore    struct amr_softc            *sc = ac->ac_sc;
1198105419Semoore    struct amr_sgentry          *sg;
1199105419Semoore    struct amr_passthrough      *ap = (struct amr_passthrough *)ac->ac_data;
1200106252Semoore    struct amr_ext_passthrough	*aep = (struct amr_ext_passthrough *)ac->ac_data;
1201105419Semoore    int                         i;
120265245Smsmith
120365245Smsmith    /* get base address of s/g table */
120465245Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
120565245Smsmith
1206105419Semoore    /* decide whether we need to populate the s/g table */
1207106225Semoore    if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
1208106225Semoore	if (nsegments < 2) {
1209106225Semoore	    aep->ap_no_sg_elements = 0;
1210106225Semoore	    aep->ap_data_transfer_address =  segs[0].ds_addr;
1211106225Semoore	} else {
1212106225Semoore	    /* save s/g table information in passthrough */
1213106225Semoore	    aep->ap_no_sg_elements = nsegments;
1214138422Sscottl	    aep->ap_data_transfer_address = sc->amr_sgbusaddr +
1215138422Sscottl		(ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1216138422Sscottl	    /*
1217138422Sscottl	     * populate s/g table (overwrites previous call which mapped the
1218138422Sscottl	     * passthrough)
1219138422Sscottl	     */
1220106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1221106225Semoore		sg->sg_addr = segs[i].ds_addr;
1222106225Semoore		sg->sg_count = segs[i].ds_len;
1223106225Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1224106225Semoore	    }
1225106225Semoore	}
1226138422Sscottl	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x\n",
1227138422Sscottl	    ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address,
1228138422Sscottl	    ac->ac_dataphys);
1229105419Semoore    } else {
1230106225Semoore	if (nsegments < 2) {
1231106225Semoore	    ap->ap_no_sg_elements = 0;
1232106225Semoore	    ap->ap_data_transfer_address =  segs[0].ds_addr;
1233106225Semoore	} else {
1234106225Semoore	    /* save s/g table information in passthrough */
1235106225Semoore	    ap->ap_no_sg_elements = nsegments;
1236138422Sscottl	    ap->ap_data_transfer_address = sc->amr_sgbusaddr +
1237138422Sscottl		(ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1238138422Sscottl	    /*
1239138422Sscottl	     * populate s/g table (overwrites previous call which mapped the
1240138422Sscottl	     * passthrough)
1241138422Sscottl	     */
1242106225Semoore	    for (i = 0; i < nsegments; i++, sg++) {
1243105419Semoore		sg->sg_addr = segs[i].ds_addr;
1244105419Semoore		sg->sg_count = segs[i].ds_len;
1245105419Semoore		debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
1246106225Semoore	    }
1247105419Semoore	}
1248138422Sscottl	debug(3, "slot %d  %d segments at 0x%x, passthrough at 0x%x",
1249138422Sscottl	    ac->ac_slot, ap->ap_no_sg_elements, ap->ap_data_transfer_address,
1250138422Sscottl	    ac->ac_dataphys);
1251105419Semoore    }
1252138422Sscottl    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
1253138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1254138422Sscottl	    BUS_DMASYNC_PREREAD);
1255138422Sscottl    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
1256138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1257138422Sscottl	    BUS_DMASYNC_PREWRITE);
1258138422Sscottl    if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0)
1259138422Sscottl	panic("no direction for ccb?\n");
1260138422Sscottl
1261138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAIN)
1262138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
1263138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAOUT)
1264138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE);
1265138422Sscottl
1266138422Sscottl    ac->ac_flags |= AMR_CMD_MAPPED;
1267138422Sscottl
1268138422Sscottl    amr_start1(sc, ac);
126951974Smsmith}
127051974Smsmith
1271138422Sscottlstatic int
127251974Smsmithamr_mapcmd(struct amr_command *ac)
127351974Smsmith{
127451974Smsmith    struct amr_softc	*sc = ac->ac_sc;
127551974Smsmith
127669319Smsmith    debug_called(3);
127751974Smsmith
127865245Smsmith    /* if the command involves data at all, and hasn't been mapped */
1279138422Sscottl    if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) {
1280138422Sscottl	if (ac->ac_ccb_data == NULL) {
128165245Smsmith	    /* map the data buffers into bus space and build the s/g list */
1282138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1283138422Sscottl		ac->ac_length, amr_setup_data_dmamap, ac, 0) == EINPROGRESS) {
1284138422Sscottl		sc->amr_state |= AMR_STATE_QUEUE_FRZN;
1285138422Sscottl	    }
1286138422Sscottl	} else {
1287138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data,
1288138422Sscottl		ac->ac_length, amr_setup_dmamap, ac, BUS_DMA_NOWAIT) != 0){
1289138422Sscottl		return (ENOMEM);
1290138422Sscottl	    }
1291138422Sscottl	    if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1292138422Sscottl		ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac,
1293138422Sscottl		0) == EINPROGRESS) {
1294138422Sscottl		sc->amr_state |= AMR_STATE_QUEUE_FRZN;
1295138422Sscottl	    }
1296143121Sscottl     }
1297143121Sscottl   } else if ((ac->ac_flags & AMR_CMD_MAPPED) == 0) {
1298143121Sscottl    	amr_start1(sc, ac);
1299143121Sscottl   }
1300143121Sscottl
1301138422Sscottl    return (0);
130251974Smsmith}
130351974Smsmith
130451974Smsmithstatic void
130551974Smsmithamr_unmapcmd(struct amr_command *ac)
130651974Smsmith{
130751974Smsmith    struct amr_softc	*sc = ac->ac_sc;
130851974Smsmith
130969319Smsmith    debug_called(3);
131051974Smsmith
131165245Smsmith    /* if the command involved data at all and was mapped */
131265245Smsmith    if (ac->ac_flags & AMR_CMD_MAPPED) {
131351974Smsmith
131465245Smsmith	if (ac->ac_data != NULL) {
131565245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAIN)
1316138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap,
1317138422Sscottl		    BUS_DMASYNC_POSTREAD);
131865245Smsmith	    if (ac->ac_flags & AMR_CMD_DATAOUT)
1319138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap,
1320138422Sscottl		    BUS_DMASYNC_POSTWRITE);
132165245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
132265245Smsmith	}
132365245Smsmith
132465245Smsmith	if (ac->ac_ccb_data != NULL) {
132565245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
1326138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1327138422Sscottl		    BUS_DMASYNC_POSTREAD);
132865245Smsmith	    if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
1329138422Sscottl		bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
1330138422Sscottl		    BUS_DMASYNC_POSTWRITE);
133165245Smsmith	    bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap);
133265245Smsmith	}
133365245Smsmith	ac->ac_flags &= ~AMR_CMD_MAPPED;
133451974Smsmith    }
133551974Smsmith}
133651974Smsmith
1337138422Sscottlstatic void
1338138422Sscottlamr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
1339138422Sscottl{
1340138422Sscottl    struct amr_command *ac = arg;
1341138422Sscottl    struct amr_softc *sc = ac->ac_sc;
1342138422Sscottl
1343138422Sscottl    amr_setup_dmamap(arg, segs, nsegs, err);
1344138422Sscottl
1345138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAIN)
1346138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
1347138422Sscottl    if (ac->ac_flags & AMR_CMD_DATAOUT)
1348138422Sscottl	bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE);
1349138422Sscottl    ac->ac_flags |= AMR_CMD_MAPPED;
1350138422Sscottl
1351138422Sscottl    amr_start1(sc, ac);
1352138422Sscottl}
1353138422Sscottl
135451974Smsmith/********************************************************************************
135565245Smsmith * Take a command and give it to the controller, returns 0 if successful, or
135665245Smsmith * EBUSY if the command should be retried later.
135751974Smsmith */
135851974Smsmithstatic int
135951974Smsmithamr_start(struct amr_command *ac)
136051974Smsmith{
1361138422Sscottl    struct amr_softc *sc;
1362138422Sscottl    int error = 0;
1363105419Semoore
136469319Smsmith    debug_called(3);
136551974Smsmith
136665245Smsmith    /* mark command as busy so that polling consumer can tell */
1367138422Sscottl    sc = ac->ac_sc;
136865245Smsmith    ac->ac_flags |= AMR_CMD_BUSY;
136965245Smsmith
137065245Smsmith    /* get a command slot (freed in amr_done) */
1371140340Sscottl    if (amr_getslot(ac)) {
137265245Smsmith	return(EBUSY);
1373140340Sscottl    }
137465245Smsmith
1375138422Sscottl    /* Now we have a slot, we can map the command (unmapped in amr_complete). */
1376138422Sscottl    if ((error = amr_mapcmd(ac)) == ENOMEM) {
1377138422Sscottl	/*
1378138422Sscottl	 * Memroy resources are short, so free the slot and let this be tried
1379138422Sscottl	 * later.
1380138422Sscottl	 */
1381138422Sscottl	sc->amr_busycmd[ac->ac_slot] = NULL;
1382138422Sscottl	sc->amr_busyslots--;
1383138422Sscottl    }
138465245Smsmith
1385138422Sscottl    return (error);
1386138422Sscottl}
1387138422Sscottl
1388138422Sscottl
1389138422Sscottlstatic int
1390138422Sscottlamr_start1(struct amr_softc *sc, struct amr_command *ac)
1391138422Sscottl{
1392138422Sscottl    int			done, s, i;
1393138422Sscottl
139465245Smsmith    /* mark the new mailbox we are going to copy in as busy */
139565245Smsmith    ac->ac_mailbox.mb_busy = 1;
139665245Smsmith
139765245Smsmith    /* clear the poll/ack fields in the mailbox */
139865245Smsmith    sc->amr_mailbox->mb_poll = 0;
139965245Smsmith    sc->amr_mailbox->mb_ack = 0;
140065245Smsmith
140151974Smsmith    /*
140251974Smsmith     * Save the slot number so that we can locate this command when complete.
140351974Smsmith     * Note that ident = 0 seems to be special, so we don't use it.
140451974Smsmith     */
140551974Smsmith    ac->ac_mailbox.mb_ident = ac->ac_slot + 1;
140651974Smsmith
140758883Smsmith    /*
140865245Smsmith     * Spin waiting for the mailbox, give up after ~1 second.  We expect the
140965245Smsmith     * controller to be able to handle our I/O.
141065245Smsmith     *
141165245Smsmith     * XXX perhaps we should wait for less time, and count on the deferred command
141265245Smsmith     * handling to deal with retries?
141358883Smsmith     */
141469319Smsmith    debug(4, "wait for mailbox");
141558883Smsmith    for (i = 10000, done = 0; (i > 0) && !done; i--) {
141651974Smsmith	s = splbio();
141751974Smsmith
141851974Smsmith	/* is the mailbox free? */
141951974Smsmith	if (sc->amr_mailbox->mb_busy == 0) {
142069319Smsmith	    debug(4, "got mailbox");
142151974Smsmith	    sc->amr_mailbox64->mb64_segment = 0;
142265245Smsmith	    bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
142351974Smsmith	    done = 1;
142451974Smsmith
142565245Smsmith	    /* not free, spin waiting */
142651974Smsmith	} else {
142769319Smsmith	    debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy);
142858883Smsmith	    /* this is somewhat ugly */
142958883Smsmith	    DELAY(100);
143051974Smsmith	}
143158883Smsmith	splx(s);	/* drop spl to allow completion interrupts */
143251974Smsmith    }
143365245Smsmith
143465245Smsmith    /*
143565245Smsmith     * Now give the command to the controller
143665245Smsmith     */
143751974Smsmith    if (done) {
143865245Smsmith	if (sc->amr_submit_command(sc)) {
143965245Smsmith	    /* the controller wasn't ready to take the command, forget that we tried to post it */
144065245Smsmith	    sc->amr_mailbox->mb_busy = 0;
144165245Smsmith	    return(EBUSY);
144265245Smsmith	}
144369319Smsmith	debug(3, "posted command");
144451974Smsmith	return(0);
144551974Smsmith    }
144651974Smsmith
144751974Smsmith    /*
144865245Smsmith     * The controller wouldn't take the command.  Return the command as busy
144965245Smsmith     * so that it is retried later.
145051974Smsmith     */
145165245Smsmith    return(EBUSY);
145251974Smsmith}
145351974Smsmith
145451974Smsmith/********************************************************************************
145551974Smsmith * Extract one or more completed commands from the controller (sc)
145651974Smsmith *
145752543Smsmith * Returns nonzero if any commands on the work queue were marked as completed.
145851974Smsmith */
1459140340Sscottl
146065245Smsmithint
146151974Smsmithamr_done(struct amr_softc *sc)
146251974Smsmith{
146351974Smsmith    struct amr_command	*ac;
146451974Smsmith    struct amr_mailbox	mbox;
146565245Smsmith    int			i, idx, result;
146651974Smsmith
146769319Smsmith    debug_called(3);
146851974Smsmith
146951974Smsmith    /* See if there's anything for us to do */
147051974Smsmith    result = 0;
147151974Smsmith
147258883Smsmith    /* loop collecting completed commands */
147358883Smsmith    for (;;) {
147458883Smsmith	/* poll for a completed command's identifier and status */
147558883Smsmith	if (sc->amr_get_work(sc, &mbox)) {
147658883Smsmith	    result = 1;
147758883Smsmith
147858883Smsmith	    /* iterate over completed commands in this result */
147958883Smsmith	    for (i = 0; i < mbox.mb_nstatus; i++) {
148058883Smsmith		/* get pointer to busy command */
148158883Smsmith		idx = mbox.mb_completed[i] - 1;
148258883Smsmith		ac = sc->amr_busycmd[idx];
148351974Smsmith
148458883Smsmith		/* really a busy command? */
148558883Smsmith		if (ac != NULL) {
148658883Smsmith
148758883Smsmith		    /* pull the command from the busy index */
148858883Smsmith		    sc->amr_busycmd[idx] = NULL;
148965245Smsmith		    sc->amr_busyslots--;
149051974Smsmith
149165245Smsmith		    /* save status for later use */
149265245Smsmith		    ac->ac_status = mbox.mb_status;
149365245Smsmith		    amr_enqueue_completed(ac);
149465245Smsmith		    debug(3, "completed command with status %x", mbox.mb_status);
149565245Smsmith		} else {
149665245Smsmith		    device_printf(sc->amr_dev, "bad slot %d completed\n", idx);
149751974Smsmith		}
149851974Smsmith	    }
149958883Smsmith	} else {
150065245Smsmith	    break;	/* no work */
150151974Smsmith	}
150251974Smsmith    }
1503138422Sscottl
150458883Smsmith    /* handle completion and timeouts */
1505140340Sscottl    amr_complete(sc, 0);
1506138422Sscottl
150751974Smsmith    return(result);
150851974Smsmith}
150951974Smsmith
151051974Smsmith/********************************************************************************
151151974Smsmith * Do completion processing on done commands on (sc)
151251974Smsmith */
1513140340Sscottl
151451974Smsmithstatic void
151565245Smsmithamr_complete(void *context, int pending)
151651974Smsmith{
151765245Smsmith    struct amr_softc	*sc = (struct amr_softc *)context;
151865245Smsmith    struct amr_command	*ac;
151951974Smsmith
152069319Smsmith    debug_called(3);
152151974Smsmith
152265245Smsmith    /* pull completed commands off the queue */
152365245Smsmith    for (;;) {
152465245Smsmith	ac = amr_dequeue_completed(sc);
152565245Smsmith	if (ac == NULL)
152665245Smsmith	    break;
152758883Smsmith
152865245Smsmith	/* unmap the command's data buffer */
152965245Smsmith	amr_unmapcmd(ac);
153051974Smsmith
153165245Smsmith	/* unbusy the command */
153265245Smsmith	ac->ac_flags &= ~AMR_CMD_BUSY;
153351974Smsmith
153465245Smsmith	/*
153565245Smsmith	 * Is there a completion handler?
153665245Smsmith	 */
153765245Smsmith	if (ac->ac_complete != NULL) {
153865245Smsmith	    ac->ac_complete(ac);
153965245Smsmith
154051974Smsmith	    /*
154165245Smsmith	     * Is someone sleeping on this one?
154251974Smsmith	     */
154365245Smsmith	} else if (ac->ac_flags & AMR_CMD_SLEEP) {
154465245Smsmith	    wakeup(ac);
154551974Smsmith	}
1546109031Semoore
1547109031Semoore	if(!sc->amr_busyslots) {
1548109031Semoore	    wakeup(sc);
1549109031Semoore	}
155051974Smsmith    }
1551140340Sscottl
1552140340Sscottl    sc->amr_state &= ~AMR_STATE_QUEUE_FRZN;
1553140340Sscottl    amr_startio(sc);
155451974Smsmith}
155551974Smsmith
155651974Smsmith/********************************************************************************
155751974Smsmith ********************************************************************************
155851974Smsmith                                                        Command Buffer Management
155951974Smsmith ********************************************************************************
156051974Smsmith ********************************************************************************/
156151974Smsmith
156251974Smsmith/********************************************************************************
156351974Smsmith * Get a new command buffer.
156451974Smsmith *
156551974Smsmith * This may return NULL in low-memory cases.
156651974Smsmith *
156751974Smsmith * If possible, we recycle a command buffer that's been used before.
156851974Smsmith */
156965245Smsmithstruct amr_command *
157051974Smsmithamr_alloccmd(struct amr_softc *sc)
157151974Smsmith{
157251974Smsmith    struct amr_command	*ac;
157351974Smsmith
157465245Smsmith    debug_called(3);
157551974Smsmith
157665245Smsmith    ac = amr_dequeue_free(sc);
157751974Smsmith    if (ac == NULL) {
157865245Smsmith	amr_alloccmd_cluster(sc);
157965245Smsmith	ac = amr_dequeue_free(sc);
158051974Smsmith    }
1581140340Sscottl    if (ac == NULL) {
1582140340Sscottl	sc->amr_state |= AMR_STATE_QUEUE_FRZN;
158365245Smsmith	return(NULL);
1584140340Sscottl    }
158565245Smsmith
158665245Smsmith    /* clear out significant fields */
158765245Smsmith    ac->ac_status = 0;
158851974Smsmith    bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox));
158965245Smsmith    ac->ac_flags = 0;
159065245Smsmith    ac->ac_bio = NULL;
159165245Smsmith    ac->ac_data = NULL;
159265245Smsmith    ac->ac_ccb_data = NULL;
159365245Smsmith    ac->ac_complete = NULL;
159451974Smsmith    return(ac);
159551974Smsmith}
159651974Smsmith
159751974Smsmith/********************************************************************************
159851974Smsmith * Release a command buffer for recycling.
159951974Smsmith */
160065245Smsmithvoid
160151974Smsmithamr_releasecmd(struct amr_command *ac)
160251974Smsmith{
160365245Smsmith    debug_called(3);
160451974Smsmith
160565245Smsmith    amr_enqueue_free(ac);
160651974Smsmith}
160751974Smsmith
160851974Smsmith/********************************************************************************
160965245Smsmith * Allocate a new command cluster and initialise it.
161051974Smsmith */
1611104094Sphkstatic void
161265245Smsmithamr_alloccmd_cluster(struct amr_softc *sc)
161351974Smsmith{
161465245Smsmith    struct amr_command_cluster	*acc;
161565245Smsmith    struct amr_command		*ac;
1616140340Sscottl    int				s, i, nextslot;
161751974Smsmith
1618140340Sscottl    if (sc->amr_nextslot > sc->amr_maxio)
1619140340Sscottl	return;
1620140340Sscottl    acc = malloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
162165245Smsmith    if (acc != NULL) {
162265245Smsmith	s = splbio();
1623140340Sscottl	nextslot = sc->amr_nextslot;
162465245Smsmith	TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link);
162565245Smsmith	splx(s);
162665245Smsmith	for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
162765245Smsmith	    ac = &acc->acc_command[i];
162865245Smsmith	    ac->ac_sc = sc;
1629140340Sscottl	    ac->ac_slot = nextslot;
163065245Smsmith	    if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) &&
163165245Smsmith		!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap))
163265245Smsmith		amr_releasecmd(ac);
1633140340Sscottl	    if (++nextslot > sc->amr_maxio)
1634140340Sscottl		break;
163565245Smsmith	}
1636140340Sscottl	sc->amr_nextslot = nextslot;
163765245Smsmith    }
163851974Smsmith}
163951974Smsmith
164051974Smsmith/********************************************************************************
164165245Smsmith * Free a command cluster
164265245Smsmith */
1643104094Sphkstatic void
164465245Smsmithamr_freecmd_cluster(struct amr_command_cluster *acc)
164565245Smsmith{
164665245Smsmith    struct amr_softc	*sc = acc->acc_command[0].ac_sc;
164765245Smsmith    int			i;
164865245Smsmith
164965245Smsmith    for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++)
165065245Smsmith	bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap);
165165245Smsmith    free(acc, M_DEVBUF);
165265245Smsmith}
165365245Smsmith
165465245Smsmith/********************************************************************************
165551974Smsmith ********************************************************************************
165651974Smsmith                                                         Interface-specific Shims
165751974Smsmith ********************************************************************************
165851974Smsmith ********************************************************************************/
165951974Smsmith
166051974Smsmith/********************************************************************************
166151974Smsmith * Tell the controller that the mailbox contains a valid command
166251974Smsmith */
166365245Smsmithstatic int
166451974Smsmithamr_quartz_submit_command(struct amr_softc *sc)
166551974Smsmith{
166665245Smsmith    debug_called(3);
166751974Smsmith
166865245Smsmith    if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT)
166965245Smsmith	return(EBUSY);
167051974Smsmith    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
167165245Smsmith    return(0);
167251974Smsmith}
167351974Smsmith
167465245Smsmithstatic int
167551974Smsmithamr_std_submit_command(struct amr_softc *sc)
167651974Smsmith{
167765245Smsmith    debug_called(3);
167851974Smsmith
167965245Smsmith    if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG)
168065245Smsmith	return(EBUSY);
168151974Smsmith    AMR_SPOST_COMMAND(sc);
168265245Smsmith    return(0);
168351974Smsmith}
168451974Smsmith
168551974Smsmith/********************************************************************************
168651974Smsmith * Claim any work that the controller has completed; acknowledge completion,
168751974Smsmith * save details of the completion in (mbsave)
168851974Smsmith */
168951974Smsmithstatic int
169051974Smsmithamr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
169151974Smsmith{
169251974Smsmith    int		s, worked;
169351974Smsmith    u_int32_t	outd;
1694140340Sscottl    u_int8_t	nstatus;
169551974Smsmith
169665245Smsmith    debug_called(3);
169765245Smsmith
169851974Smsmith    worked = 0;
169951974Smsmith    s = splbio();
170051974Smsmith
170151974Smsmith    /* work waiting for us? */
170251974Smsmith    if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) {
170351974Smsmith
1704140340Sscottl	/* acknowledge interrupt */
1705140340Sscottl	AMR_QPUT_ODB(sc, AMR_QODB_READY);
1706140340Sscottl
1707140340Sscottl	while ((nstatus = sc->amr_mailbox->mb_nstatus) == 0xff)
1708140340Sscottl	    ;
1709140340Sscottl	sc->amr_mailbox->mb_nstatus = 0xff;
1710140340Sscottl
171151974Smsmith	/* save mailbox, which contains a list of completed commands */
171265245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
1713140340Sscottl	mbsave->mb_nstatus = nstatus;
171451974Smsmith
171551974Smsmith	/* acknowledge that we have the commands */
1716140340Sscottl	AMR_QPUT_IDB(sc, AMR_QIDB_ACK);
171765245Smsmith
171865763Smsmith#ifndef AMR_QUARTZ_GOFASTER
171965245Smsmith	/*
172065245Smsmith	 * This waits for the controller to notice that we've taken the
172165245Smsmith	 * command from it.  It's very inefficient, and we shouldn't do it,
172265245Smsmith	 * but if we remove this code, we stop completing commands under
172365245Smsmith	 * load.
172465245Smsmith	 *
172565245Smsmith	 * Peter J says we shouldn't do this.  The documentation says we
172665245Smsmith	 * should.  Who is right?
172765245Smsmith	 */
172851974Smsmith	while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
172951974Smsmith	    ;				/* XXX aiee! what if it dies? */
173065245Smsmith#endif
173165245Smsmith
173251974Smsmith	worked = 1;			/* got some work */
173351974Smsmith    }
173451974Smsmith
173551974Smsmith    splx(s);
173651974Smsmith    return(worked);
173751974Smsmith}
173851974Smsmith
173951974Smsmithstatic int
174051974Smsmithamr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
174151974Smsmith{
174251974Smsmith    int		s, worked;
174351974Smsmith    u_int8_t	istat;
174451974Smsmith
174565245Smsmith    debug_called(3);
174651974Smsmith
174751974Smsmith    worked = 0;
174851974Smsmith    s = splbio();
174951974Smsmith
175051974Smsmith    /* check for valid interrupt status */
175151974Smsmith    istat = AMR_SGET_ISTAT(sc);
175251974Smsmith    if ((istat & AMR_SINTR_VALID) != 0) {
175351974Smsmith	AMR_SPUT_ISTAT(sc, istat);	/* ack interrupt status */
175451974Smsmith
175551974Smsmith	/* save mailbox, which contains a list of completed commands */
175665245Smsmith	bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
175751974Smsmith
175851974Smsmith	AMR_SACK_INTERRUPT(sc);		/* acknowledge we have the mailbox */
175951974Smsmith	worked = 1;
176051974Smsmith    }
176151974Smsmith
176251974Smsmith    splx(s);
176351974Smsmith    return(worked);
176451974Smsmith}
176551974Smsmith
176651974Smsmith/********************************************************************************
176751974Smsmith * Notify the controller of the mailbox location.
176851974Smsmith */
176951974Smsmithstatic void
177051974Smsmithamr_std_attach_mailbox(struct amr_softc *sc)
177151974Smsmith{
177251974Smsmith
177351974Smsmith    /* program the mailbox physical address */
177451974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_0, sc->amr_mailboxphys         & 0xff);
177551974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_1, (sc->amr_mailboxphys >>  8) & 0xff);
177651974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_2, (sc->amr_mailboxphys >> 16) & 0xff);
177751974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_3, (sc->amr_mailboxphys >> 24) & 0xff);
177851974Smsmith    AMR_SBYTE_SET(sc, AMR_SMBOX_ENABLE, AMR_SMBOX_ADDR);
177951974Smsmith
178051974Smsmith    /* clear any outstanding interrupt and enable interrupts proper */
178151974Smsmith    AMR_SACK_INTERRUPT(sc);
178251974Smsmith    AMR_SENABLE_INTR(sc);
178351974Smsmith}
178451974Smsmith
178565245Smsmith#ifdef AMR_BOARD_INIT
178651974Smsmith/********************************************************************************
178765245Smsmith * Initialise the controller
178865245Smsmith */
178965245Smsmithstatic int
179065245Smsmithamr_quartz_init(struct amr_softc *sc)
179165245Smsmith{
179265245Smsmith    int		status, ostatus;
179365245Smsmith
179465245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_QGET_INITSTATUS(sc));
179565245Smsmith
179665245Smsmith    AMR_QRESET(sc);
179765245Smsmith
179865245Smsmith    ostatus = 0xff;
179965245Smsmith    while ((status = AMR_QGET_INITSTATUS(sc)) != AMR_QINIT_DONE) {
180065245Smsmith	if (status != ostatus) {
180165245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_qinit, status));
180265245Smsmith	    ostatus = status;
180365245Smsmith	}
180465245Smsmith	switch (status) {
180565245Smsmith	case AMR_QINIT_NOMEM:
180665245Smsmith	    return(ENOMEM);
180765245Smsmith
180865245Smsmith	case AMR_QINIT_SCAN:
180965245Smsmith	    /* XXX we could print channel/target here */
181065245Smsmith	    break;
181165245Smsmith	}
181265245Smsmith    }
181365245Smsmith    return(0);
181465245Smsmith}
181565245Smsmith
181665245Smsmithstatic int
181765245Smsmithamr_std_init(struct amr_softc *sc)
181865245Smsmith{
181965245Smsmith    int		status, ostatus;
182065245Smsmith
182165245Smsmith    device_printf(sc->amr_dev, "initial init status %x\n", AMR_SGET_INITSTATUS(sc));
182265245Smsmith
182365245Smsmith    AMR_SRESET(sc);
182465245Smsmith
182565245Smsmith    ostatus = 0xff;
182665245Smsmith    while ((status = AMR_SGET_INITSTATUS(sc)) != AMR_SINIT_DONE) {
182765245Smsmith	if (status != ostatus) {
182865245Smsmith	    device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_sinit, status));
182965245Smsmith	    ostatus = status;
183065245Smsmith	}
183165245Smsmith	switch (status) {
183265245Smsmith	case AMR_SINIT_NOMEM:
183365245Smsmith	    return(ENOMEM);
183465245Smsmith
183565245Smsmith	case AMR_SINIT_INPROG:
183665245Smsmith	    /* XXX we could print channel/target here? */
183765245Smsmith	    break;
183865245Smsmith	}
183965245Smsmith    }
184065245Smsmith    return(0);
184165245Smsmith}
184265245Smsmith#endif
184365245Smsmith
184465245Smsmith/********************************************************************************
184551974Smsmith ********************************************************************************
184651974Smsmith                                                                        Debugging
184751974Smsmith ********************************************************************************
184851974Smsmith ********************************************************************************/
184951974Smsmith
185051974Smsmith/********************************************************************************
185165245Smsmith * Identify the controller and print some information about it.
185265245Smsmith */
185365245Smsmithstatic void
185465245Smsmithamr_describe_controller(struct amr_softc *sc)
185565245Smsmith{
185665245Smsmith    struct amr_prodinfo	*ap;
185765245Smsmith    struct amr_enquiry	*ae;
185865245Smsmith    char		*prod;
185965245Smsmith
1860140340Sscottl    mtx_lock(&sc->amr_io_lock);
186165245Smsmith    /*
186265245Smsmith     * Try to get 40LD product info, which tells us what the card is labelled as.
186365245Smsmith     */
186465245Smsmith    if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) {
1865105419Semoore	device_printf(sc->amr_dev, "<LSILogic %.80s> Firmware %.16s, BIOS %.16s, %dMB RAM\n",
186665245Smsmith		      ap->ap_product, ap->ap_firmware, ap->ap_bios,
186765245Smsmith		      ap->ap_memsize);
186865245Smsmith
186965245Smsmith	free(ap, M_DEVBUF);
1870140340Sscottl	mtx_unlock(&sc->amr_io_lock);
187165245Smsmith	return;
187265245Smsmith    }
187365245Smsmith
187465245Smsmith    /*
187565245Smsmith     * Try 8LD extended ENQUIRY to get controller signature, and use lookup table.
187665245Smsmith     */
187765245Smsmith    if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) {
187865245Smsmith	prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature);
187965245Smsmith
188065245Smsmith    } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) {
188165245Smsmith
188265245Smsmith	/*
188365245Smsmith	 * Try to work it out based on the PCI signatures.
188465245Smsmith	 */
188565245Smsmith	switch (pci_get_device(sc->amr_dev)) {
188665245Smsmith	case 0x9010:
188765245Smsmith	    prod = "Series 428";
188865245Smsmith	    break;
188965245Smsmith	case 0x9060:
189065245Smsmith	    prod = "Series 434";
189165245Smsmith	    break;
189265245Smsmith	default:
189365245Smsmith	    prod = "unknown controller";
189465245Smsmith	    break;
189565245Smsmith	}
189665245Smsmith    } else {
1897144369Ssam	device_printf(sc->amr_dev, "<unsupported controller>\n");
1898144369Ssam	mtx_unlock(&sc->amr_io_lock);
1899144369Ssam	return;
190065245Smsmith    }
190174936Shm
190274936Shm    /*
190374936Shm     * HP NetRaid controllers have a special encoding of the firmware and
190474936Shm     * BIOS versions. The AMI version seems to have it as strings whereas
190574936Shm     * the HP version does it with a leading uppercase character and two
190674936Shm     * binary numbers.
190774936Shm     */
190874936Shm
190974936Shm    if(ae->ae_adapter.aa_firmware[2] >= 'A' &&
191074936Shm       ae->ae_adapter.aa_firmware[2] <= 'Z' &&
191174936Shm       ae->ae_adapter.aa_firmware[1] <  ' ' &&
191274936Shm       ae->ae_adapter.aa_firmware[0] <  ' ' &&
191374936Shm       ae->ae_adapter.aa_bios[2] >= 'A'     &&
191474936Shm       ae->ae_adapter.aa_bios[2] <= 'Z'     &&
191574936Shm       ae->ae_adapter.aa_bios[1] <  ' '     &&
191674936Shm       ae->ae_adapter.aa_bios[0] <  ' ') {
191774936Shm
191874936Shm	/* this looks like we have an HP NetRaid version of the MegaRaid */
191974936Shm
192074936Shm    	if(ae->ae_signature == AMR_SIG_438) {
1921108470Sschweikh    		/* the AMI 438 is a NetRaid 3si in HP-land */
192274936Shm    		prod = "HP NetRaid 3si";
192374936Shm    	}
192474936Shm
192574936Shm	device_printf(sc->amr_dev, "<%s> Firmware %c.%02d.%02d, BIOS %c.%02d.%02d, %dMB RAM\n",
192674936Shm		      prod, ae->ae_adapter.aa_firmware[2],
192774936Shm		      ae->ae_adapter.aa_firmware[1],
192874936Shm		      ae->ae_adapter.aa_firmware[0],
192974936Shm		      ae->ae_adapter.aa_bios[2],
193074936Shm		      ae->ae_adapter.aa_bios[1],
193174936Shm		      ae->ae_adapter.aa_bios[0],
193274936Shm		      ae->ae_adapter.aa_memorysize);
193374936Shm    } else {
193474936Shm	device_printf(sc->amr_dev, "<%s> Firmware %.4s, BIOS %.4s, %dMB RAM\n",
193574936Shm		      prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios,
193674936Shm		      ae->ae_adapter.aa_memorysize);
193774936Shm    }
193865245Smsmith    free(ae, M_DEVBUF);
1939140340Sscottl    mtx_unlock(&sc->amr_io_lock);
194065245Smsmith}
194165245Smsmith
1942120988Spsint
1943120988Spsamr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks)
1944120988Sps{
1945120988Sps    struct amr_command	*ac;
1946120988Sps    int			error = EIO;
1947120988Sps
1948120988Sps    debug_called(1);
1949120988Sps
1950140688Sscottl    sc->amr_state |= AMR_STATE_INTEN;
1951120988Sps
1952120988Sps    /* get ourselves a command buffer */
1953120988Sps    if ((ac = amr_alloccmd(sc)) == NULL)
1954120988Sps	goto out;
1955120988Sps    /* set command flags */
1956120988Sps    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
1957120988Sps
1958120988Sps    /* point the command at our data */
1959120988Sps    ac->ac_data = data;
1960120988Sps    ac->ac_length = blks * AMR_BLKSIZE;
1961120988Sps
1962120988Sps    /* build the command proper */
1963120988Sps    ac->ac_mailbox.mb_command 	= AMR_CMD_LWRITE;
1964120988Sps    ac->ac_mailbox.mb_blkcount	= blks;
1965120988Sps    ac->ac_mailbox.mb_lba	= lba;
1966120988Sps    ac->ac_mailbox.mb_drive	= unit;
1967120988Sps
1968120988Sps    /* can't assume that interrupts are going to work here, so play it safe */
1969120988Sps    if (sc->amr_poll_command(ac))
1970120988Sps	goto out;
1971120988Sps    error = ac->ac_status;
1972120988Sps
1973120988Sps out:
1974120988Sps    if (ac != NULL)
1975120988Sps	amr_releasecmd(ac);
1976120988Sps
1977140688Sscottl    sc->amr_state &= ~AMR_STATE_INTEN;
1978120988Sps    return (error);
1979120988Sps}
1980120988Sps
1981120988Sps
1982120988Sps
198365245Smsmith#ifdef AMR_DEBUG
198465245Smsmith/********************************************************************************
198551974Smsmith * Print the command (ac) in human-readable format
198651974Smsmith */
1987107756Semoore#if 0
198851974Smsmithstatic void
198951974Smsmithamr_printcommand(struct amr_command *ac)
199051974Smsmith{
199151974Smsmith    struct amr_softc	*sc = ac->ac_sc;
199251974Smsmith    struct amr_sgentry	*sg;
199351974Smsmith    int			i;
199451974Smsmith
199551974Smsmith    device_printf(sc->amr_dev, "cmd %x  ident %d  drive %d\n",
199651974Smsmith		  ac->ac_mailbox.mb_command, ac->ac_mailbox.mb_ident, ac->ac_mailbox.mb_drive);
199751974Smsmith    device_printf(sc->amr_dev, "blkcount %d  lba %d\n",
199851974Smsmith		  ac->ac_mailbox.mb_blkcount, ac->ac_mailbox.mb_lba);
199954512Speter    device_printf(sc->amr_dev, "virtaddr %p  length %lu\n", ac->ac_data, (unsigned long)ac->ac_length);
200058883Smsmith    device_printf(sc->amr_dev, "sg physaddr %08x  nsg %d\n",
200151974Smsmith		  ac->ac_mailbox.mb_physaddr, ac->ac_mailbox.mb_nsgelem);
200265245Smsmith    device_printf(sc->amr_dev, "ccb %p  bio %p\n", ac->ac_ccb_data, ac->ac_bio);
200351974Smsmith
200451974Smsmith    /* get base address of s/g table */
200551974Smsmith    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
200651974Smsmith    for (i = 0; i < ac->ac_mailbox.mb_nsgelem; i++, sg++)
200751974Smsmith	device_printf(sc->amr_dev, "  %x/%d\n", sg->sg_addr, sg->sg_count);
200851974Smsmith}
200965245Smsmith#endif
2010107756Semoore#endif
2011