amr.c revision 57297
1/*-
2 * Copyright (c) 1999 Michael Smith
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$FreeBSD: head/sys/dev/amr/amr.c 57297 2000-02-17 23:33:57Z msmith $
27 */
28
29/*
30 * Driver for the AMI MegaRaid family of controllers
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/kernel.h>
37
38#include <sys/buf.h>
39#include <sys/bus.h>
40#include <sys/conf.h>
41#include <sys/devicestat.h>
42#include <sys/disk.h>
43
44#include <machine/resource.h>
45#include <machine/bus.h>
46#include <machine/clock.h>
47#include <sys/rman.h>
48
49#include <dev/amr/amrio.h>
50#include <dev/amr/amrreg.h>
51#include <dev/amr/amrvar.h>
52
53#if 0
54#define debug(fmt, args...)	printf("%s: " fmt "\n", __FUNCTION__ , ##args)
55#else
56#define debug(fmt, args...)
57#endif
58
59#define AMR_CDEV_MAJOR	132
60
61static struct cdevsw amr_cdevsw = {
62		/* open */	amr_open,
63		/* close */	amr_close,
64		/* read */	noread,
65		/* write */	nowrite,
66		/* ioctl */	amr_ioctl,
67		/* poll */	nopoll,
68		/* mmap */	nommap,
69		/* strategy */	nostrategy,
70		/* name */ 	"amr",
71		/* maj */	AMR_CDEV_MAJOR,
72		/* dump */	nodump,
73		/* psize */ 	nopsize,
74		/* flags */	0,
75		/* bmaj */	254	/* XXX magic no-bdev */
76};
77
78static int	cdev_registered = 0;
79devclass_t	amr_devclass;
80
81/*
82 * Command wrappers
83 */
84static int			amr_query_controller(struct amr_softc *sc);
85static void			*amr_enquiry(struct amr_softc *sc, size_t bufsize,
86					     u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual);
87static int			amr_flush(struct amr_softc *sc);
88static void			amr_startio(struct amr_softc *sc);
89static void			amr_completeio(struct amr_command *ac);
90
91/*
92 * Command processing.
93 */
94static int			amr_wait_command(struct amr_command *ac);
95static int			amr_poll_command(struct amr_command *ac);
96static int			amr_getslot(struct amr_command *ac);
97static void			amr_mapcmd(struct amr_command *ac);
98static void			amr_unmapcmd(struct amr_command *ac);
99static int			amr_start(struct amr_command *ac);
100static int			amr_done(struct amr_softc *sc);
101static void			amr_complete(struct amr_softc *sc);
102
103/*
104 * Command buffer allocation.
105 */
106static struct amr_command	*amr_alloccmd(struct amr_softc *sc);
107static void			amr_releasecmd(struct amr_command *ac);
108static void			amr_freecmd(struct amr_command *ac);
109
110/*
111 * Interface-specific shims
112 */
113static void			amr_quartz_submit_command(struct amr_softc *sc);
114static int			amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
115static void			amr_quartz_attach_mailbox(struct amr_softc *sc);
116
117static void			amr_std_submit_command(struct amr_softc *sc);
118static int			amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
119static void			amr_std_attach_mailbox(struct amr_softc *sc);
120
121/*
122 * Debugging
123 */
124static void			amr_printcommand(struct amr_command *ac);
125
126/********************************************************************************
127 ********************************************************************************
128                                                                Public Interfaces
129 ********************************************************************************
130 ********************************************************************************/
131
132/********************************************************************************
133 * Free all of the resources associated with (sc)
134 *
135 * Should not be called if the controller is active.
136 */
137void
138amr_free(struct amr_softc *sc)
139{
140    struct amr_command	*ac;
141    u_int8_t		*p;
142
143    debug("called");
144
145
146    /* throw away any command buffers */
147    while ((ac = TAILQ_FIRST(&sc->amr_freecmds)) != NULL) {
148	TAILQ_REMOVE(&sc->amr_freecmds, ac, ac_link);
149	amr_freecmd(ac);
150    }
151
152    /* destroy data-transfer DMA tag */
153    if (sc->amr_buffer_dmat)
154	bus_dma_tag_destroy(sc->amr_buffer_dmat);
155
156    /* free and destroy DMA memory and tag for s/g lists */
157    if (sc->amr_sgtable)
158	bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap);
159    if (sc->amr_sg_dmat)
160	bus_dma_tag_destroy(sc->amr_sg_dmat);
161
162    /* free and destroy DMA memory and tag for mailbox */
163    if (sc->amr_mailbox) {
164	p = (u_int8_t *)sc->amr_mailbox;
165	bus_dmamem_free(sc->amr_sg_dmat, p - 16, sc->amr_sg_dmamap);
166    }
167    if (sc->amr_sg_dmat)
168	bus_dma_tag_destroy(sc->amr_sg_dmat);
169
170    /* disconnect the interrupt handler */
171    if (sc->amr_intr)
172	bus_teardown_intr(sc->amr_dev, sc->amr_irq, sc->amr_intr);
173    if (sc->amr_irq != NULL)
174	bus_release_resource(sc->amr_dev, SYS_RES_IRQ, 0, sc->amr_irq);
175
176    /* destroy the parent DMA tag */
177    if (sc->amr_parent_dmat)
178	bus_dma_tag_destroy(sc->amr_parent_dmat);
179
180    /* release the register window mapping */
181    if (sc->amr_reg != NULL)
182	bus_release_resource(sc->amr_dev,
183			     (sc->amr_type == AMR_TYPE_QUARTZ) ? SYS_RES_MEMORY : SYS_RES_IOPORT,
184			     AMR_CFG_BASE, sc->amr_reg);
185}
186
187/********************************************************************************
188 * Allocate and map the scatter/gather table in bus space.
189 */
190static void
191amr_dma_map_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
192{
193    struct amr_softc	*sc = (struct amr_softc *)arg;
194
195    debug("called");
196
197    /* save base of s/g table's address in bus space */
198    sc->amr_sgbusaddr = segs->ds_addr;
199}
200
201static int
202amr_sglist_map(struct amr_softc *sc)
203{
204    size_t	segsize;
205    int		error;
206
207    debug("called");
208
209    /* destroy any existing mappings */
210    if (sc->amr_sgtable)
211	bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap);
212    if (sc->amr_sg_dmat)
213	bus_dma_tag_destroy(sc->amr_sg_dmat);
214
215    /*
216     * Create a single tag describing a region large enough to hold all of
217     * the s/g lists we will need.
218     */
219    segsize = sizeof(struct amr_sgentry) * AMR_NSEG * sc->amr_maxio;
220    error = bus_dma_tag_create(sc->amr_parent_dmat, 	/* parent */
221			       1, 0, 			/* alignment, boundary */
222			       BUS_SPACE_MAXADDR,	/* lowaddr */
223			       BUS_SPACE_MAXADDR, 	/* highaddr */
224			       NULL, NULL, 		/* filter, filterarg */
225			       segsize, 1,		/* maxsize, nsegments */
226			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
227			       0,			/* flags */
228			       &sc->amr_sg_dmat);
229    if (error != 0) {
230	device_printf(sc->amr_dev, "can't allocate scatter/gather DMA tag\n");
231	return(ENOMEM);
232    }
233
234    /*
235     * Allocate enough s/g maps for all commands and permanently map them into
236     * controller-visible space.
237     *
238     * XXX this assumes we can get enough space for all the s/g maps in one
239     * contiguous slab.  We may need to switch to a more complex arrangement where
240     * we allocate in smaller chunks and keep a lookup table from slot to bus address.
241     */
242    error = bus_dmamem_alloc(sc->amr_sg_dmat, (void **)&sc->amr_sgtable, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap);
243    if (error) {
244	device_printf(sc->amr_dev, "can't allocate s/g table\n");
245	return(ENOMEM);
246    }
247    bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, sc->amr_sgtable, segsize, amr_dma_map_sg, sc, 0);
248    return(0);
249}
250
251/********************************************************************************
252 * Allocate and set up mailbox areas for the controller (sc)
253 *
254 * The basic mailbox structure should be 16-byte aligned.  This means that the
255 * mailbox64 structure has 4 bytes hanging off the bottom.
256 */
257static void
258amr_map_mailbox(void *arg, bus_dma_segment_t *segs, int nseg, int error)
259{
260    struct amr_softc	*sc = (struct amr_softc *)arg;
261
262    debug("called");
263
264    /* save phsyical base of the basic mailbox structure */
265    sc->amr_mailboxphys = segs->ds_addr + 16;
266}
267
268static int
269amr_setup_mbox(struct amr_softc *sc)
270{
271    int		error;
272    u_int8_t	*p;
273
274    debug("called");
275
276    /*
277     * Create a single tag describing a region large enough to hold the entire
278     * mailbox.
279     */
280    error = bus_dma_tag_create(sc->amr_parent_dmat,	/* parent */
281			       16, 0,			/* alignment, boundary */
282			       BUS_SPACE_MAXADDR,	/* lowaddr */
283			       BUS_SPACE_MAXADDR,	/* highaddr */
284			       NULL, NULL,		/* filter, filterarg */
285			       sizeof(struct amr_mailbox) + 16, 1, /* maxsize, nsegments */
286			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
287			       0,			/* flags */
288			       &sc->amr_mailbox_dmat);
289    if (error != 0) {
290	device_printf(sc->amr_dev, "can't allocate mailbox tag\n");
291	return(ENOMEM);
292    }
293
294    /*
295     * Allocate the mailbox structure and permanently map it into
296     * controller-visible space.
297     */
298    error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void **)&p, BUS_DMA_NOWAIT,
299			     &sc->amr_mailbox_dmamap);
300    if (error) {
301	device_printf(sc->amr_dev, "can't allocate mailbox memory\n");
302	return(ENOMEM);
303    }
304    bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p,
305		    sizeof(struct amr_mailbox64), amr_map_mailbox, sc, 0);
306    /*
307     * Conventional mailbox is inside the mailbox64 region.
308     */
309    bzero(p, sizeof(struct amr_mailbox64));
310    sc->amr_mailbox64 = (struct amr_mailbox64 *)(p + 12);
311    sc->amr_mailbox = (struct amr_mailbox *)(p + 16);
312
313    if (sc->amr_type == AMR_TYPE_STD) {
314	/* XXX we have to tell the controller where we put it */
315    }
316    return(0);
317}
318
319
320/********************************************************************************
321 * Initialise the controller and softc.
322 */
323int
324amr_attach(struct amr_softc *sc)
325{
326    int			rid, error;
327
328    /*
329     * Initialise per-controller queues.
330     */
331    TAILQ_INIT(&sc->amr_work);
332    TAILQ_INIT(&sc->amr_freecmds);
333    bufq_init(&sc->amr_bufq);
334
335    /*
336     * Configure for this controller type.
337     */
338    if (sc->amr_type == AMR_TYPE_QUARTZ) {
339	sc->amr_submit_command = amr_quartz_submit_command;
340	sc->amr_get_work       = amr_quartz_get_work;
341	sc->amr_attach_mailbox = amr_quartz_attach_mailbox;
342    } else {
343	sc->amr_submit_command = amr_std_submit_command;
344	sc->amr_get_work       = amr_std_get_work;
345	sc->amr_attach_mailbox = amr_std_attach_mailbox;
346    }
347
348    /*
349     * Allocate and connect our interrupt.
350     */
351    rid = 0;
352    sc->amr_irq = bus_alloc_resource(sc->amr_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
353    if (sc->amr_irq == NULL) {
354        device_printf(sc->amr_dev, "couldn't allocate interrupt\n");
355        amr_free(sc);
356        return(ENXIO);
357    }
358    error = bus_setup_intr(sc->amr_dev, sc->amr_irq, INTR_TYPE_BIO,  amr_intr, sc, &sc->amr_intr);
359    if (error) {
360        device_printf(sc->amr_dev, "couldn't set up interrupt\n");
361        amr_free(sc);
362        return(ENXIO);
363    }
364
365    /*
366     * Create DMA tag for mapping buffers into controller-addressable space.
367     */
368    error = bus_dma_tag_create(sc->amr_parent_dmat,     /* parent */
369                               1, 0,                    /* alignment, boundary */
370                               BUS_SPACE_MAXADDR,       /* lowaddr */
371                               BUS_SPACE_MAXADDR,       /* highaddr */
372                               NULL, NULL,              /* filter, filterarg */
373                               MAXBSIZE, AMR_NSEG,      /* maxsize, nsegments */
374                               BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
375                               0,                       /* flags */
376                               &sc->amr_buffer_dmat);
377    if (error != 0) {
378        device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n");
379        return(ENOMEM);
380    }
381
382    /*
383     * Allocate and set up mailbox in a bus-visible fashion, attach to controller.
384     */
385    if ((error = amr_setup_mbox(sc)) != 0)
386	return(error);
387    sc->amr_attach_mailbox(sc);
388
389    /*
390     * Build a temporary set of scatter/gather buffers.
391     */
392    sc->amr_maxio = 2;
393    if (amr_sglist_map(sc))
394	return(ENXIO);
395
396    /*
397     * Quiz controller for features and limits.
398     */
399    if (amr_query_controller(sc))
400	return(ENXIO);
401
402    /*
403     * Rebuild the scatter/gather buffers now we know how many we need.
404     */
405    if (amr_sglist_map(sc))
406	return(ENXIO);
407
408    return(0);
409}
410
411/********************************************************************************
412 * Locate disk resources and attach children to them.
413 */
414void
415amr_startup(struct amr_softc *sc)
416{
417    struct amr_logdrive	*dr;
418    int			i, error;
419
420    debug("called");
421
422    /* get up-to-date drive information */
423    if (amr_query_controller(sc)) {
424	device_printf(sc->amr_dev, "couldn't scan controller for drives\n");
425	return;
426    }
427
428    /* iterate over available drives */
429    for (i = 0, dr = &sc->amr_drive[0]; (i < AMR_MAXLD) && (dr->al_size != 0xffffffff); i++, dr++) {
430	/* are we already attached to this drive? */
431	if (dr->al_disk == 0) {
432	    /* generate geometry information */
433	    if (dr->al_size > 0x200000) {	/* extended translation? */
434		dr->al_heads = 255;
435		dr->al_sectors = 63;
436	    } else {
437		dr->al_heads = 64;
438		dr->al_sectors = 32;
439	    }
440	    dr->al_cylinders = dr->al_size / (dr->al_heads * dr->al_sectors);
441
442	    dr->al_disk = device_add_child(sc->amr_dev, NULL, -1);
443	    if (dr->al_disk == 0)
444		device_printf(sc->amr_dev, "device_add_child failed\n");
445	    device_set_ivars(dr->al_disk, dr);
446	}
447    }
448
449    if ((error = bus_generic_attach(sc->amr_dev)) != 0)
450	device_printf(sc->amr_dev, "bus_generic_attach returned %d\n", error);
451
452    /* mark controller back up */
453    sc->amr_state &= ~AMR_STATE_SHUTDOWN;
454
455    /* interrupts will be enabled before we do anything more */
456    sc->amr_state |= AMR_STATE_INTEN;
457}
458
459/********************************************************************************
460 * Disconnect from the controller completely, in preparation for unload.
461 */
462int
463amr_detach(device_t dev)
464{
465    struct amr_softc	*sc = device_get_softc(dev);
466    int			error;
467
468    debug("called");
469
470    if (sc->amr_state & AMR_STATE_OPEN)
471	return(EBUSY);
472
473    if ((error = amr_shutdown(dev)))
474	return(error);
475
476    amr_free(sc);
477
478    /*
479     * Deregister the control device on last detach.
480     */
481    if (--cdev_registered == 0)
482	cdevsw_remove(&amr_cdevsw);
483
484    return(0);
485}
486
487/********************************************************************************
488 * Bring the controller down to a dormant state and detach all child devices.
489 *
490 * This function is called before detach, system shutdown, or before performing
491 * an operation which may add or delete system disks.  (Call amr_startup to
492 * resume normal operation.)
493 *
494 * Note that we can assume that the bufq on the controller is empty, as we won't
495 * allow shutdown if any device is open.
496 */
497int
498amr_shutdown(device_t dev)
499{
500    struct amr_softc	*sc = device_get_softc(dev);
501    struct amrd_softc	*ad;
502    int			i, s, error;
503
504    debug("called");
505
506    s = splbio();
507    error = 0;
508
509    /* assume we're going to shut down */
510    sc->amr_state |= AMR_STATE_SHUTDOWN;
511    for (i = 0; i < AMR_MAXLD; i++) {
512	if (sc->amr_drive[i].al_disk != 0) {
513	    ad = device_get_softc(sc->amr_drive[i].al_disk);
514	    if (ad->amrd_flags & AMRD_OPEN) {		/* drive is mounted, abort shutdown */
515		sc->amr_state &= ~AMR_STATE_SHUTDOWN;
516		device_printf(sc->amr_drive[i].al_disk, "still open, can't shutdown\n");
517		error = EBUSY;
518		goto out;
519	    }
520	}
521    }
522
523    /* flush controller */
524    device_printf(sc->amr_dev, "flushing cache...");
525    if (amr_flush(sc)) {
526	printf("failed\n");
527    } else {
528	printf("done\n");
529    }
530
531    /* delete all our child devices */
532    for (i = 0; i < AMR_MAXLD; i++) {
533	if (sc->amr_drive[i].al_disk != 0) {
534	    if ((error = device_delete_child(sc->amr_dev, sc->amr_drive[i].al_disk)) != 0)
535		goto out;
536	    sc->amr_drive[i].al_disk = 0;
537	}
538    }
539    bus_generic_detach(sc->amr_dev);
540
541 out:
542    splx(s);
543    return(error);
544}
545
546/********************************************************************************
547 * Bring the controller to a quiescent state, ready for system suspend.
548 */
549int
550amr_suspend(device_t dev)
551{
552    struct amr_softc	*sc = device_get_softc(dev);
553
554    debug("called");
555
556    sc->amr_state |= AMR_STATE_SUSPEND;
557
558    /* flush controller */
559    device_printf(sc->amr_dev, "flushing cache...");
560    printf("%s\n", amr_flush(sc) ? "failed" : "done");
561
562    return(0);
563}
564
565/********************************************************************************
566 * Bring the controller back to a state ready for operation.
567 */
568int
569amr_resume(device_t dev)
570{
571    struct amr_softc	*sc = device_get_softc(dev);
572
573    debug("called");
574
575    sc->amr_state &= ~AMR_STATE_SUSPEND;
576
577    return(0);
578}
579
580/*******************************************************************************
581 * Take an interrupt, or be poked by other code to look for interrupt-worthy
582 * status.
583 */
584void
585amr_intr(void *arg)
586{
587    struct amr_softc	*sc = (struct amr_softc *)arg;
588    int			worked;
589
590    debug("called on %p", sc);
591
592    /* spin collecting finished commands, process them if we find anything */
593    worked = 0;
594    while (amr_done(sc))
595	worked = 1;
596    if (worked)
597	amr_complete(sc);
598};
599
600/*******************************************************************************
601 * Receive a buf structure from a child device and queue it on a particular
602 * disk resource, then poke the disk resource to start as much work as it can.
603 */
604int
605amr_submit_buf(struct amr_softc *sc, struct buf *bp)
606{
607    int		s;
608
609    debug("called");
610
611    s = splbio();
612    bufq_insert_tail(&sc->amr_bufq, bp);
613    splx(s);
614    sc->amr_waitbufs++;
615    amr_startio(sc);
616    return(0);
617}
618
619/********************************************************************************
620 * Accept an open operation on the control device.
621 */
622int
623amr_open(dev_t dev, int flags, int fmt, struct proc *p)
624{
625    int			unit = minor(dev);
626    struct amr_softc	*sc = devclass_get_softc(amr_devclass, unit);
627
628    sc->amr_state |= AMR_STATE_OPEN;
629    return(0);
630}
631
632/********************************************************************************
633 * Accept the last close on the control device.
634 */
635int
636amr_close(dev_t dev, int flags, int fmt, struct proc *p)
637{
638    int			unit = minor(dev);
639    struct amr_softc	*sc = devclass_get_softc(amr_devclass, unit);
640
641    sc->amr_state &= ~AMR_STATE_OPEN;
642    return (0);
643}
644
645/********************************************************************************
646 * Handle controller-specific control operations.
647 */
648int
649amr_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
650{
651
652    switch(cmd) {
653    default:
654	return(ENOTTY);
655    }
656}
657
658/********************************************************************************
659 * Handle operations requested by a drive connected to this controller.
660 */
661int
662amr_submit_ioctl(struct amr_softc *sc, struct amr_logdrive *drive, u_long cmd,
663		 caddr_t addr, int32_t flag, struct proc *p)
664{
665    return(ENOTTY);
666}
667
668/********************************************************************************
669 ********************************************************************************
670                                                                 Command Wrappers
671 ********************************************************************************
672 ********************************************************************************/
673
674/********************************************************************************
675 * Interrogate the controller for the operational parameters we require.
676 */
677static int
678amr_query_controller(struct amr_softc *sc)
679{
680    void	*buf;
681    int		i;
682
683    /* try to issue an ENQUIRY3 command */
684    if ((buf = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
685			   AMR_CONFIG_ENQ3_SOLICITED_FULL)) == NULL) {
686
687	struct amr_enquiry	*ae;
688
689	/* failed, try the old ENQUIRY command */
690	if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) {
691	    device_printf(sc->amr_dev, "could not obtain configuration data from controller\n");
692	    return(1);
693	}
694	/* first-time enquiry? */
695	if (sc->amr_maxdrives == 0) {
696	    device_printf(sc->amr_dev, "firmware %.4s bios %.4s  %dMB memory\n",
697			  ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios,
698			  ae->ae_adapter.aa_memorysize);
699	}
700	sc->amr_maxdrives = 8;
701	sc->amr_maxio = ae->ae_adapter.aa_maxio;
702	for (i = 0; i < ae->ae_ldrv.al_numdrives; i++) {
703	    sc->amr_drive[i].al_size = ae->ae_ldrv.al_size[i];
704	    sc->amr_drive[i].al_state = ae->ae_ldrv.al_state[i];
705	    sc->amr_drive[i].al_properties = ae->ae_ldrv.al_properties[i];
706	    debug("  drive %d: %d state %x properties %x\n", i, sc->amr_drive[i].al_size,
707		  sc->amr_drive[i].al_state, sc->amr_drive[i].al_properties);
708	}
709	for (; i < AMR_MAXLD; i++)
710	    sc->amr_drive[i].al_size = 0xffffffff;
711	free(ae, M_DEVBUF);
712    } else {
713	free(buf, M_DEVBUF);
714	sc->amr_maxdrives = 40;
715
716	/* get static product info */
717	if ((buf = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODINFO, 0)) == NULL) {
718	    device_printf(sc->amr_dev, "controller supports 40ld but CONFIG_PRODINFO failed\n");
719	    return(1);
720	}
721	free(buf, M_DEVBUF);
722	device_printf(sc->amr_dev, "40LD firmware unsupported; send controller to msmith@freebsd.org\n");
723	return(1);
724    }
725    return(0);
726}
727
728/********************************************************************************
729 * Run a generic enquiry-style command.
730 */
731static void *
732amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
733{
734    struct amr_command	*ac;
735    void		*result;
736    u_int8_t		*mbox;
737    int			error;
738
739    debug("called");
740
741    error = 1;
742    result = NULL;
743
744    /* get ourselves a command buffer */
745    if ((ac = amr_alloccmd(sc)) == NULL)
746	goto out;
747    /* allocate the response structure */
748    if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL)
749	goto out;
750    /* get a command slot */
751    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
752    if (amr_getslot(ac))
753	goto out;
754
755    /* map the command so the controller can see it */
756    ac->ac_data = result;
757    ac->ac_length = bufsize;
758    amr_mapcmd(ac);
759
760    /* build the command proper */
761    mbox = (u_int8_t *)&ac->ac_mailbox;		/* XXX want a real structure for this? */
762    mbox[0] = cmd;
763    mbox[2] = cmdsub;
764    mbox[3] = cmdqual;
765    ac->ac_mailbox.mb_physaddr = ac->ac_dataphys;
766
767    /* run the command in polled/wait mode as suits the current mode */
768    if ((sc->amr_state & AMR_STATE_INTEN) ? amr_wait_command(ac) : amr_poll_command(ac))
769	goto out;
770    error = ac->ac_status;
771
772 out:
773    if (ac != NULL)
774	amr_releasecmd(ac);
775    if ((error != 0) && (result != NULL)) {
776	free(result, M_DEVBUF);
777	result = NULL;
778    }
779    return(result);
780}
781
782/********************************************************************************
783 * Flush the controller's internal cache, return status.
784 */
785static int
786amr_flush(struct amr_softc *sc)
787{
788    struct amr_command	*ac;
789    int			error;
790
791    /* get ourselves a command buffer */
792    error = 1;
793    if ((ac = amr_alloccmd(sc)) == NULL)
794	goto out;
795    /* get a command slot */
796    ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
797    if (amr_getslot(ac))
798	goto out;
799
800    /* build the command proper */
801    ac->ac_mailbox.mb_command = AMR_CMD_FLUSH;
802
803    /* run the command in polled/wait mode as suits the current mode */
804    if ((sc->amr_state & AMR_STATE_INTEN) ? amr_wait_command(ac) : amr_poll_command(ac))
805	goto out;
806    error = ac->ac_status;
807
808 out:
809    if (ac != NULL)
810	amr_releasecmd(ac);
811    return(error);
812}
813
814/********************************************************************************
815 * Pull as much work off the softc's work queue as possible and give it to the
816 * controller.  Leave a couple of slots free for emergencies.
817 *
818 * We avoid running at splbio() whenever possible.
819 */
820static void
821amr_startio(struct amr_softc *sc)
822{
823    struct amr_command	*ac;
824    struct amrd_softc	*amrd;
825    struct buf		*bp;
826    int			blkcount;
827    int			driveno;
828    int			cmd;
829    int			s;
830
831    /* spin until something prevents us from doing any work */
832    s = splbio();
833    for (;;) {
834
835	/* see if there's work to be done */
836	if ((bp = bufq_first(&sc->amr_bufq)) == NULL)
837	    break;
838	/* get a command */
839	if ((ac = amr_alloccmd(sc)) == NULL)
840	    break;
841	/* get a slot for the command */
842	if (amr_getslot(ac) != 0) {
843	    amr_releasecmd(ac);
844	    break;
845	}
846	/* get the buf containing our work */
847	bufq_remove(&sc->amr_bufq, bp);
848	sc->amr_waitbufs--;
849	splx(s);
850
851	/* connect the buf to the command */
852	ac->ac_complete = amr_completeio;
853	ac->ac_private = bp;
854	ac->ac_data = bp->b_data;
855	ac->ac_length = bp->b_bcount;
856	if (bp->b_flags & B_READ) {
857	    ac->ac_flags |= AMR_CMD_DATAIN;
858	    cmd = AMR_CMD_LREAD;
859	} else {
860	    ac->ac_flags |= AMR_CMD_DATAOUT;
861	    cmd = AMR_CMD_LWRITE;
862	}
863
864	/* map the command so the controller can work with it */
865	amr_mapcmd(ac);
866
867	/* build a suitable I/O command (assumes 512-byte rounded transfers) */
868	amrd = (struct amrd_softc *)bp->b_driver1;
869	driveno = amrd->amrd_drive - &sc->amr_drive[0];
870	blkcount = bp->b_bcount / AMR_BLKSIZE;
871
872	if ((bp->b_pblkno + blkcount) > sc->amr_drive[driveno].al_size)
873	    device_printf(sc->amr_dev, "I/O beyond end of unit (%u,%d > %u)\n",
874			  bp->b_pblkno, blkcount, sc->amr_drive[driveno].al_size);
875
876	/*
877	 * Build the I/O command.
878	 */
879	ac->ac_mailbox.mb_command = cmd;
880	ac->ac_mailbox.mb_blkcount = blkcount;
881	ac->ac_mailbox.mb_lba = bp->b_pblkno;
882	ac->ac_mailbox.mb_physaddr = ac->ac_sgphys;
883	ac->ac_mailbox.mb_drive = driveno;
884	ac->ac_mailbox.mb_nsgelem = ac->ac_nsgent;
885
886	/* try to give command to controller */
887	if (amr_start(ac) != 0) {
888	    /* fail the command */
889	    ac->ac_status = AMR_STATUS_WEDGED;
890	    amr_completeio(ac);
891	}
892	s = splbio();
893    }
894    splx(s);
895}
896
897/********************************************************************************
898 * Handle completion of an I/O command.
899 */
900static void
901amr_completeio(struct amr_command *ac)
902{
903    struct amr_softc	*sc = ac->ac_sc;
904    struct buf		*bp = (struct buf *)ac->ac_private;
905
906    if (ac->ac_status != AMR_STATUS_SUCCESS) {	/* could be more verbose here? */
907	bp->b_error = EIO;
908	bp->b_flags |= B_ERROR;
909
910	switch(ac->ac_status) {
911	    /* XXX need more information on I/O error reasons */
912	default:
913	    device_printf(sc->amr_dev, "I/O error - %x\n", ac->ac_status);
914	    amr_printcommand(ac);
915	    break;
916	}
917    }
918    amr_releasecmd(ac);
919    amrd_intr(bp);
920}
921
922/********************************************************************************
923 ********************************************************************************
924                                                               Command Processing
925 ********************************************************************************
926 ********************************************************************************/
927
928/********************************************************************************
929 * Take a command, submit it to the controller and sleep until it completes
930 * or fails.  Interrupts must be enabled, returns nonzero on error.
931 */
932static int
933amr_wait_command(struct amr_command *ac)
934{
935    struct amr_softc	*sc = ac->ac_sc;
936    int			error, count;
937
938    debug("called");
939
940    ac->ac_complete = NULL;
941    ac->ac_private = ac;
942    if ((error = amr_start(ac)) != 0)
943	return(error);
944
945    count = 0;
946    /* XXX better timeout? */
947    while ((ac->ac_status == AMR_STATUS_BUSY) && (count < 30)) {
948	tsleep(ac->ac_private, PRIBIO | PCATCH, "amrwcmd", hz);
949    }
950
951    if (ac->ac_status != 0) {
952	device_printf(sc->amr_dev, "I/O error 0x%x\n", ac->ac_status);
953	return(EIO);
954    }
955    return(0);
956}
957
958/********************************************************************************
959 * Take a command, submit it to the controller and busy-wait for it to return.
960 * Returns nonzero on error.  Can be safely called with interrupts enabled.
961 */
962static int
963amr_poll_command(struct amr_command *ac)
964{
965    struct amr_softc	*sc = ac->ac_sc;
966    int			error, count, s;
967
968    debug("called");
969
970    ac->ac_complete = NULL;
971    ac->ac_private = NULL;
972    if ((error = amr_start(ac)) != 0)
973	return(error);
974
975    count = 0;
976    do {
977	/*
978	 * Poll for completion, although the interrupt handler may beat us to it.
979	 * Note that the timeout here is somewhat arbitrary.
980	 */
981	amr_done(sc);
982    } while ((ac->ac_status == AMR_STATUS_BUSY) && (count++ < 100000));
983    s = splbio();
984    if (ac->ac_status != AMR_STATUS_BUSY) {
985	TAILQ_REMOVE(&sc->amr_work, ac, ac_link);
986	sc->amr_workcount--;
987	error = 0;
988    } else {
989	/* take the command out of the busy list, mark slot as bogus */
990	sc->amr_busycmd[ac->ac_slot] = (struct amr_command *)sc;
991	error = EIO;
992	device_printf(sc->amr_dev, "I/O error 0x%x\n", ac->ac_status);
993    }
994    splx(s);
995    return(error);
996}
997
998/********************************************************************************
999 * Get a free command slot.
1000 */
1001static int
1002amr_getslot(struct amr_command *ac)
1003{
1004    struct amr_softc	*sc = ac->ac_sc;
1005    int			s, slot, limit;
1006
1007    debug("called");
1008
1009    /* enforce slot usage limit */
1010    limit = (ac->ac_flags & AMR_CMD_PRIORITY) ? sc->amr_maxio : sc->amr_maxio - 4;
1011    if (sc->amr_busycmdcount > limit)
1012	return(EBUSY);
1013
1014    /*
1015     * Allocate a slot
1016     */
1017    s = splbio();
1018    for (slot = 0; slot < sc->amr_maxio; slot++) {
1019	if (sc->amr_busycmd[slot] == NULL)
1020	    break;
1021    }
1022    if (slot < sc->amr_maxio) {
1023	sc->amr_busycmdcount++;
1024	sc->amr_busycmd[slot] = ac;
1025    }
1026    splx(s);
1027
1028    /* out of slots? */
1029    if (slot >= sc->amr_maxio)
1030	return(EBUSY);
1031
1032    ac->ac_slot = slot;
1033    return(0);
1034}
1035
1036/********************************************************************************
1037 * Map/unmap (ac)'s data in the controller's addressable space.
1038 */
1039static void
1040amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
1041{
1042    struct amr_command	*ac = (struct amr_command *)arg;
1043    struct amr_softc	*sc = ac->ac_sc;
1044    struct amr_sgentry	*sg;
1045    int			i;
1046
1047    debug("called");
1048
1049    /* get base address of s/g table */
1050    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
1051
1052    /* save s/g table information in command */
1053    ac->ac_nsgent = nsegments;
1054    ac->ac_sgphys = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
1055    ac->ac_dataphys = segs[0].ds_addr;
1056
1057    /* populate s/g table */
1058    for (i = 0; i < nsegments; i++, sg++) {
1059	sg->sg_addr = segs[i].ds_addr;
1060	sg->sg_count = segs[i].ds_len;
1061    }
1062}
1063
1064static void
1065amr_mapcmd(struct amr_command *ac)
1066{
1067    struct amr_softc	*sc = ac->ac_sc;
1068
1069    debug("called");
1070
1071    /* if the command involves data at all */
1072    if (ac->ac_data != NULL) {
1073
1074	/* map the data buffer into bus space and build the s/g list */
1075	bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, ac->ac_length,
1076			amr_setup_dmamap, ac, 0);
1077	if (ac->ac_flags & AMR_CMD_DATAIN)
1078	    bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREREAD);
1079	if (ac->ac_flags & AMR_CMD_DATAOUT)
1080	    bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREWRITE);
1081    }
1082}
1083
1084static void
1085amr_unmapcmd(struct amr_command *ac)
1086{
1087    struct amr_softc	*sc = ac->ac_sc;
1088
1089    debug("called");
1090
1091    /* if the command involved data at all */
1092    if (ac->ac_data != NULL) {
1093
1094	if (ac->ac_flags & AMR_CMD_DATAIN)
1095	    bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD);
1096	if (ac->ac_flags & AMR_CMD_DATAOUT)
1097	    bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTWRITE);
1098
1099	bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
1100    }
1101}
1102
1103/********************************************************************************
1104 * Take a command and give it to the controller.  Take care of any completed
1105 * commands we encouter while waiting.
1106 */
1107static int
1108amr_start(struct amr_command *ac)
1109{
1110    struct amr_softc	*sc = ac->ac_sc;
1111    int			worked, done, s, i;
1112
1113    debug("called");
1114
1115    /*
1116     * Save the slot number so that we can locate this command when complete.
1117     * Note that ident = 0 seems to be special, so we don't use it.
1118     */
1119    ac->ac_mailbox.mb_ident = ac->ac_slot + 1;
1120
1121    /* set the busy flag when we copy the mailbox in */
1122    ac->ac_mailbox.mb_busy = 1;
1123
1124    /* set impossible status so that a woken sleeper can tell the command is busy */
1125    ac->ac_status = AMR_STATUS_BUSY;
1126
1127    /* spin waiting for the mailbox */
1128    debug("wait for mailbox");
1129    for (i = 100000, done = 0, worked = 0; (i > 0) && !done; i--) {
1130	s = splbio();
1131
1132	/* is the mailbox free? */
1133	if (sc->amr_mailbox->mb_busy == 0) {
1134	    debug("got mailbox");
1135	    sc->amr_mailbox64->mb64_segment = 0;
1136	    bcopy(&ac->ac_mailbox, sc->amr_mailbox, AMR_MBOX_CMDSIZE);
1137	    sc->amr_submit_command(sc);
1138	    done = 1;
1139	    sc->amr_workcount++;
1140	    TAILQ_INSERT_TAIL(&sc->amr_work, ac, ac_link);
1141
1142	    /* not free, try to clean up while we wait */
1143	} else {
1144	    debug("busy flag %x\n", sc->amr_mailbox->mb_busy);
1145	    worked = amr_done(sc);
1146	}
1147	splx(s);
1148    }
1149
1150    /* do completion processing if we picked anything up */
1151    if (worked)
1152	amr_complete(sc);
1153
1154    /* command is enqueued? */
1155    if (done) {
1156	ac->ac_stamp = time_second;
1157	debug("posted command");
1158	return(0);
1159    }
1160
1161    /*
1162     * The controller wouldn't take the command.  Revoke the slot
1163     * that the command was given and return with a bad status.
1164     */
1165    sc->amr_busycmd[ac->ac_slot] = NULL;
1166    device_printf(sc->amr_dev, "controller wedged (not taking commands)\n");
1167    ac->ac_status = AMR_STATUS_WEDGED;
1168    return(EIO);
1169}
1170
1171/********************************************************************************
1172 * Extract one or more completed commands from the controller (sc)
1173 *
1174 * Returns nonzero if any commands on the work queue were marked as completed.
1175 */
1176static int
1177amr_done(struct amr_softc *sc)
1178{
1179    struct amr_command	*ac;
1180    struct amr_mailbox	mbox;
1181    int			i, idx, result;
1182
1183    debug("called");
1184
1185    /* See if there's anything for us to do */
1186    result = 0;
1187    if (sc->amr_get_work(sc, &mbox)) {
1188	/* iterate over completed commands */
1189	for (i = 0; i < mbox.mb_nstatus; i++) {
1190	    /* get pointer to busy command */
1191	    idx = mbox.mb_completed[i] - 1;
1192	    ac = sc->amr_busycmd[idx];
1193
1194	    /* really a busy command? */
1195	    if (ac != NULL) {
1196
1197		/* pull the command from the busy index */
1198		sc->amr_busycmd[idx] = NULL;
1199		sc->amr_busycmdcount--;
1200
1201		/* unmap data buffer */
1202		amr_unmapcmd(ac);
1203
1204		/* aborted command? */
1205		if (ac == (struct amr_command *)sc) {
1206		    device_printf(sc->amr_dev, "aborted command completed (%d)\n", idx);
1207		    ac = NULL;
1208
1209		    /* completed normally, save status */
1210		} else {
1211		    ac->ac_status = mbox.mb_status;
1212		    debug("completed command with status %x", mbox.mb_status);
1213		}
1214		result = 1;
1215	    }
1216	}
1217    }
1218    return(result);
1219}
1220
1221/********************************************************************************
1222 * Do completion processing on done commands on (sc)
1223 */
1224static void
1225amr_complete(struct amr_softc *sc)
1226{
1227    struct amr_command	*ac, *nc;
1228    int			s, count;
1229
1230    debug("called");
1231
1232    count = 0;
1233
1234    s = splbio();
1235    ac = TAILQ_FIRST(&sc->amr_work);
1236    while (ac != NULL) {
1237	nc = TAILQ_NEXT(ac, ac_link);
1238
1239	/* Skip if command is still active */
1240	if (ac->ac_status != AMR_STATUS_BUSY) {
1241
1242	    /*
1243	     * Is there a completion handler?
1244	     */
1245	    if (ac->ac_complete != NULL) {
1246
1247		/* remove and give to completion handler */
1248		TAILQ_REMOVE(&sc->amr_work, ac, ac_link);
1249		sc->amr_workcount--;
1250		ac->ac_complete(ac);
1251
1252		/*
1253		 * Is someone sleeping on this one?
1254		 */
1255	    } else if (ac->ac_private != NULL) {
1256
1257		/* remove and wake up */
1258		TAILQ_REMOVE(&sc->amr_work, ac, ac_link);
1259		sc->amr_workcount--;
1260		wakeup_one(ac->ac_private);
1261
1262		/*
1263		 * Leave it for a polling caller.
1264		 */
1265	    } else {
1266	    }
1267	}
1268	ac = nc;
1269    }
1270    splx(s);
1271
1272    /* queue more work if we can */
1273    amr_startio(sc);
1274}
1275
1276/********************************************************************************
1277 ********************************************************************************
1278                                                        Command Buffer Management
1279 ********************************************************************************
1280 ********************************************************************************/
1281
1282/********************************************************************************
1283 * Get a new command buffer.
1284 *
1285 * This may return NULL in low-memory cases.
1286 *
1287 * Note that using malloc() is expensive (the command buffer is << 1 page) but
1288 * necessary if we are to be a loadable module before the zone allocator is fixed.
1289 *
1290 * If possible, we recycle a command buffer that's been used before.
1291 *
1292 * XXX Note that command buffers are not cleaned out - it is the caller's
1293 *     responsibility to ensure that all required fields are filled in before
1294 *     using a buffer.
1295 */
1296static struct amr_command *
1297amr_alloccmd(struct amr_softc *sc)
1298{
1299    struct amr_command	*ac;
1300    int			error;
1301    int			s;
1302
1303    debug("called");
1304
1305    s = splbio();
1306    if ((ac = TAILQ_FIRST(&sc->amr_freecmds)) != NULL)
1307	TAILQ_REMOVE(&sc->amr_freecmds, ac, ac_link);
1308    splx(s);
1309
1310    /* allocate a new command buffer? */
1311    if (ac == NULL) {
1312	ac = (struct amr_command *)malloc(sizeof(*ac), M_DEVBUF, M_NOWAIT);
1313	if (ac != NULL) {
1314	    bzero(ac, sizeof(*ac));
1315	    ac->ac_sc = sc;
1316	    error = bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap);
1317	    if (error) {
1318		free(ac, M_DEVBUF);
1319		return(NULL);
1320	    }
1321	}
1322    }
1323    bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox));
1324    return(ac);
1325}
1326
1327/********************************************************************************
1328 * Release a command buffer for recycling.
1329 *
1330 * XXX It might be a good idea to limit the number of commands we save for reuse
1331 *     if it's shown that this list bloats out massively.
1332 */
1333static void
1334amr_releasecmd(struct amr_command *ac)
1335{
1336    int		s;
1337
1338    debug("called");
1339
1340    s = splbio();
1341    TAILQ_INSERT_HEAD(&ac->ac_sc->amr_freecmds, ac, ac_link);
1342    splx(s);
1343}
1344
1345/********************************************************************************
1346 * Permanently discard a command buffer.
1347 */
1348static void
1349amr_freecmd(struct amr_command *ac)
1350{
1351    struct amr_softc	*sc = ac->ac_sc;
1352
1353    debug("called");
1354
1355    bus_dmamap_destroy(sc->amr_buffer_dmat, ac->ac_dmamap);
1356    free(ac, M_DEVBUF);
1357}
1358
1359/********************************************************************************
1360 ********************************************************************************
1361                                                         Interface-specific Shims
1362 ********************************************************************************
1363 ********************************************************************************/
1364
1365/********************************************************************************
1366 * Tell the controller that the mailbox contains a valid command
1367 */
1368static void
1369amr_quartz_submit_command(struct amr_softc *sc)
1370{
1371    debug("called");
1372
1373    sc->amr_mailbox->mb_poll = 0;
1374    sc->amr_mailbox->mb_ack = 0;
1375    /* XXX write barrier? */
1376    while(AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT)
1377	;				/* XXX aiee! what if it dies? */
1378    AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
1379}
1380
1381static void
1382amr_std_submit_command(struct amr_softc *sc)
1383{
1384    debug("called");
1385
1386    /* XXX write barrier? */
1387    while (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG)
1388	;				/* XXX aiee! what if it dies? */
1389    AMR_SPOST_COMMAND(sc);
1390}
1391
1392/********************************************************************************
1393 * Claim any work that the controller has completed; acknowledge completion,
1394 * save details of the completion in (mbsave)
1395 */
1396static int
1397amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
1398{
1399    int		s, worked;
1400    u_int32_t	outd;
1401
1402    debug("called");
1403
1404    worked = 0;
1405    s = splbio();
1406
1407    /* work waiting for us? */
1408    if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) {
1409	AMR_QPUT_ODB(sc, AMR_QODB_READY);
1410
1411	/* save mailbox, which contains a list of completed commands */
1412	/* XXX read barrier? */
1413	bcopy(sc->amr_mailbox, mbsave, sizeof(*mbsave));
1414
1415	/* acknowledge that we have the commands */
1416	AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
1417	while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
1418	    ;				/* XXX aiee! what if it dies? */
1419	worked = 1;			/* got some work */
1420    }
1421
1422    splx(s);
1423    return(worked);
1424}
1425
1426static int
1427amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
1428{
1429    int		s, worked;
1430    u_int8_t	istat;
1431
1432    debug("called");
1433
1434    worked = 0;
1435    s = splbio();
1436
1437    /* check for valid interrupt status */
1438    istat = AMR_SGET_ISTAT(sc);
1439    if ((istat & AMR_SINTR_VALID) != 0) {
1440	AMR_SPUT_ISTAT(sc, istat);	/* ack interrupt status */
1441
1442	/* save mailbox, which contains a list of completed commands */
1443	/* XXX read barrier? */
1444	bcopy(sc->amr_mailbox, mbsave, sizeof(*mbsave));
1445
1446	AMR_SACK_INTERRUPT(sc);		/* acknowledge we have the mailbox */
1447	worked = 1;
1448    }
1449
1450    splx(s);
1451    return(worked);
1452}
1453
1454/********************************************************************************
1455 * Notify the controller of the mailbox location.
1456 */
1457static void
1458amr_quartz_attach_mailbox(struct amr_softc *sc)
1459{
1460    /* Quartz is given the mailbox location when a command is submitted */
1461}
1462
1463static void
1464amr_std_attach_mailbox(struct amr_softc *sc)
1465{
1466
1467    /* program the mailbox physical address */
1468    AMR_SBYTE_SET(sc, AMR_SMBOX_0, sc->amr_mailboxphys         & 0xff);
1469    AMR_SBYTE_SET(sc, AMR_SMBOX_1, (sc->amr_mailboxphys >>  8) & 0xff);
1470    AMR_SBYTE_SET(sc, AMR_SMBOX_2, (sc->amr_mailboxphys >> 16) & 0xff);
1471    AMR_SBYTE_SET(sc, AMR_SMBOX_3, (sc->amr_mailboxphys >> 24) & 0xff);
1472    AMR_SBYTE_SET(sc, AMR_SMBOX_ENABLE, AMR_SMBOX_ADDR);
1473
1474    /* clear any outstanding interrupt and enable interrupts proper */
1475    AMR_SACK_INTERRUPT(sc);
1476    AMR_SENABLE_INTR(sc);
1477}
1478
1479/********************************************************************************
1480 ********************************************************************************
1481                                                                        Debugging
1482 ********************************************************************************
1483 ********************************************************************************/
1484
1485/********************************************************************************
1486 * Print the command (ac) in human-readable format
1487 */
1488static void
1489amr_printcommand(struct amr_command *ac)
1490{
1491    struct amr_softc	*sc = ac->ac_sc;
1492    struct amr_sgentry	*sg;
1493    int			i;
1494
1495    device_printf(sc->amr_dev, "cmd %x  ident %d  drive %d\n",
1496		  ac->ac_mailbox.mb_command, ac->ac_mailbox.mb_ident, ac->ac_mailbox.mb_drive);
1497    device_printf(sc->amr_dev, "blkcount %d  lba %d\n",
1498		  ac->ac_mailbox.mb_blkcount, ac->ac_mailbox.mb_lba);
1499    device_printf(sc->amr_dev, "virtaddr %p  length %lu\n", ac->ac_data, (unsigned long)ac->ac_length);
1500    device_printf(sc->amr_dev, "physaddr %08x  nsg %d\n",
1501		  ac->ac_mailbox.mb_physaddr, ac->ac_mailbox.mb_nsgelem);
1502
1503    /* get base address of s/g table */
1504    sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
1505    for (i = 0; i < ac->ac_mailbox.mb_nsgelem; i++, sg++)
1506	device_printf(sc->amr_dev, "  %x/%d\n", sg->sg_addr, sg->sg_count);
1507}
1508