aac.c revision 81150
1275970Scy/*-
2275970Scy * Copyright (c) 2000 Michael Smith
3275970Scy * Copyright (c) 2001 Scott Long
4275970Scy * Copyright (c) 2000 BSDi
5275970Scy * Copyright (c) 2001 Adaptec, Inc.
6275970Scy * All rights reserved.
7275970Scy *
8275970Scy * Redistribution and use in source and binary forms, with or without
9275970Scy * modification, are permitted provided that the following conditions
10275970Scy * are met:
11275970Scy * 1. Redistributions of source code must retain the above copyright
12275970Scy *    notice, this list of conditions and the following disclaimer.
13275970Scy * 2. Redistributions in binary form must reproduce the above copyright
14275970Scy *    notice, this list of conditions and the following disclaimer in the
15275970Scy *    documentation and/or other materials provided with the distribution.
16275970Scy *
17275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20275970Scy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27275970Scy * SUCH DAMAGE.
28275970Scy *
29275970Scy *	$FreeBSD: head/sys/dev/aac/aac.c 81150 2001-08-05 06:15:00Z scottl $
30275970Scy */
31275970Scy
32275970Scy/*
33275970Scy * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
34275970Scy */
35275970Scy
36275970Scy#include <sys/param.h>
37275970Scy#include <sys/systm.h>
38275970Scy#include <sys/malloc.h>
39275970Scy#include <sys/kernel.h>
40275970Scy
41275970Scy#include <dev/aac/aac_compat.h>
42275970Scy
43275970Scy#include <sys/bus.h>
44275970Scy#include <sys/conf.h>
45275970Scy#include <sys/devicestat.h>
46275970Scy#include <sys/disk.h>
47275970Scy#include <sys/file.h>
48275970Scy#include <sys/signalvar.h>
49275970Scy#include <sys/time.h>
50275970Scy
51275970Scy#include <machine/bus_memio.h>
52275970Scy#include <machine/bus.h>
53275970Scy#include <machine/resource.h>
54275970Scy
55275970Scy#include <dev/aac/aacreg.h>
56275970Scy#include <dev/aac/aac_ioctl.h>
57275970Scy#include <dev/aac/aacvar.h>
58275970Scy#include <dev/aac/aac_tables.h>
59275970Scy
60275970Scydevclass_t	aac_devclass;
61275970Scy
62275970Scystatic void	aac_startup(void *arg);
63275970Scy
64275970Scy/* Command Processing */
65275970Scystatic void	aac_startio(struct aac_softc *sc);
66275970Scystatic void	aac_timeout(struct aac_softc *sc);
67275970Scystatic int	aac_start(struct aac_command *cm);
68275970Scystatic void	aac_complete(void *context, int pending);
69275970Scystatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
70275970Scystatic void	aac_bio_complete(struct aac_command *cm);
71275970Scystatic int	aac_wait_command(struct aac_command *cm, int timeout);
72275970Scystatic void	aac_host_command(struct aac_softc *sc);
73275970Scystatic void	aac_host_response(struct aac_softc *sc);
74275970Scy
75275970Scy/* Command Buffer Management */
76275970Scystatic int	aac_alloc_command(struct aac_softc *sc,
77275970Scy				  struct aac_command **cmp);
78275970Scystatic void	aac_release_command(struct aac_command *cm);
79275970Scystatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
80275970Scy				       int nseg, int error);
81275970Scystatic int	aac_alloc_commands(struct aac_softc *sc);
82275970Scystatic void	aac_free_commands(struct aac_softc *sc);
83275970Scystatic void	aac_map_command(struct aac_command *cm);
84275970Scystatic void	aac_unmap_command(struct aac_command *cm);
85275970Scy
86275970Scy/* Hardware Interface */
87275970Scystatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
88275970Scy			       int error);
89275970Scystatic int	aac_init(struct aac_softc *sc);
90275970Scystatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
91275970Scy				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
92275970Scy				 u_int32_t arg3, u_int32_t *sp);
93275970Scystatic int	aac_sync_fib(struct aac_softc *sc, u_int32_t command,
94275970Scy			     u_int32_t xferstate, void *data,
95275970Scy			     u_int16_t datasize, void *result,
96275970Scy			     u_int16_t *resultsize);
97275970Scystatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
98275970Scy				u_int32_t fib_size, u_int32_t fib_addr);
99275970Scystatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
100275970Scy				u_int32_t *fib_size, struct aac_fib **fib_addr);
101275970Scy
102275970Scy/* StrongARM interface */
103275970Scystatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
104275970Scystatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
105275970Scystatic int	aac_sa_get_istatus(struct aac_softc *sc);
106275970Scystatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
107275970Scystatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
108275970Scy				   u_int32_t arg0, u_int32_t arg1,
109275970Scy				   u_int32_t arg2, u_int32_t arg3);
110275970Scystatic int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
111275970Scystatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
112275970Scy
113275970Scystruct aac_interface aac_sa_interface = {
114275970Scy    aac_sa_get_fwstatus,
115275970Scy    aac_sa_qnotify,
116275970Scy    aac_sa_get_istatus,
117275970Scy    aac_sa_clear_istatus,
118275970Scy    aac_sa_set_mailbox,
119275970Scy    aac_sa_get_mailboxstatus,
120275970Scy    aac_sa_set_interrupts
121275970Scy};
122275970Scy
123275970Scy/* i960Rx interface */
124275970Scystatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
125275970Scystatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
126275970Scystatic int	aac_rx_get_istatus(struct aac_softc *sc);
127275970Scystatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
128275970Scystatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
129275970Scy				   u_int32_t arg0, u_int32_t arg1,
130275970Scy				   u_int32_t arg2, u_int32_t arg3);
131275970Scystatic int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
132275970Scystatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
133275970Scy
134275970Scystruct aac_interface aac_rx_interface = {
135275970Scy    aac_rx_get_fwstatus,
136275970Scy    aac_rx_qnotify,
137275970Scy    aac_rx_get_istatus,
138275970Scy    aac_rx_clear_istatus,
139275970Scy    aac_rx_set_mailbox,
140275970Scy    aac_rx_get_mailboxstatus,
141275970Scy    aac_rx_set_interrupts
142275970Scy};
143275970Scy
144275970Scy/* Debugging and Diagnostics */
145275970Scystatic void	aac_describe_controller(struct aac_softc *sc);
146275970Scystatic char	*aac_describe_code(struct aac_code_lookup *table,
147275970Scy				   u_int32_t code);
148275970Scy
149275970Scy/* Management Interface */
150275970Scystatic d_open_t		aac_open;
151275970Scystatic d_close_t	aac_close;
152275970Scystatic d_ioctl_t	aac_ioctl;
153275970Scystatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
154275970Scystatic void		aac_handle_aif(struct aac_softc *sc,
155275970Scy				       struct aac_aif_command *aif);
156275970Scy#ifdef AAC_COMPAT_LINUX
157275970Scystatic int		aac_linux_rev_check(struct aac_softc *sc,
158275970Scy					    caddr_t udata);
159275970Scystatic int		aac_linux_getnext_aif(struct aac_softc *sc,
160275970Scy					    caddr_t arg);
161275970Scystatic int		aac_linux_return_aif(struct aac_softc *sc,
162275970Scy					    caddr_t uptr);
163275970Scy#endif
164275970Scy
165275970Scy#define AAC_CDEV_MAJOR	150
166275970Scy
167275970Scystatic struct cdevsw aac_cdevsw = {
168275970Scy    aac_open,		/* open */
169275970Scy    aac_close,		/* close */
170275970Scy    noread,		/* read */
171275970Scy    nowrite,		/* write */
172275970Scy    aac_ioctl,		/* ioctl */
173275970Scy    nopoll,		/* poll */
174275970Scy    nommap,		/* mmap */
175275970Scy    nostrategy,		/* strategy */
176275970Scy    "aac",		/* name */
177275970Scy    AAC_CDEV_MAJOR,	/* major */
178275970Scy    nodump,		/* dump */
179275970Scy    nopsize,		/* psize */
180275970Scy    0,			/* flags */
181275970Scy};
182275970Scy
183275970Scy/******************************************************************************
184275970Scy ******************************************************************************
185275970Scy				Device Interface
186275970Scy ******************************************************************************
187275970Scy ******************************************************************************/
188275970Scy
189275970Scy/******************************************************************************
190275970Scy * Initialise the controller and softc
191275970Scy */
192275970Scyint
193275970Scyaac_attach(struct aac_softc *sc)
194275970Scy{
195275970Scy    int		error, unit;
196275970Scy
197275970Scy    debug_called(1);
198275970Scy
199275970Scy    /*
200275970Scy     * Initialise per-controller queues.
201275970Scy     */
202275970Scy    aac_initq_free(sc);
203275970Scy    aac_initq_ready(sc);
204275970Scy    aac_initq_busy(sc);
205275970Scy    aac_initq_complete(sc);
206275970Scy    aac_initq_bio(sc);
207275970Scy
208275970Scy#if __FreeBSD_version >= 500005
209275970Scy    /*
210275970Scy     * Initialise command-completion task.
211275970Scy     */
212275970Scy    TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
213275970Scy#endif
214275970Scy
215275970Scy    /* disable interrupts before we enable anything */
216275970Scy    AAC_MASK_INTERRUPTS(sc);
217275970Scy
218275970Scy    /* mark controller as suspended until we get ourselves organised */
219275970Scy    sc->aac_state |= AAC_STATE_SUSPEND;
220275970Scy
221275970Scy    /*
222275970Scy     * Allocate command structures.
223275970Scy     */
224275970Scy    if ((error = aac_alloc_commands(sc)) != 0)
225275970Scy	return(error);
226275970Scy
227275970Scy    /*
228275970Scy     * Initialise the adapter.
229275970Scy     */
230275970Scy    if ((error = aac_init(sc)) != 0)
231275970Scy	return(error);
232275970Scy
233275970Scy    /*
234275970Scy     * Print a little information about the controller.
235275970Scy     */
236275970Scy    aac_describe_controller(sc);
237275970Scy
238275970Scy    /*
239275970Scy     * Register to probe our containers later.
240275970Scy     */
241275970Scy    sc->aac_ich.ich_func = aac_startup;
242275970Scy    sc->aac_ich.ich_arg = sc;
243275970Scy    if (config_intrhook_establish(&sc->aac_ich) != 0) {
244275970Scy        device_printf(sc->aac_dev, "can't establish configuration hook\n");
245275970Scy        return(ENXIO);
246275970Scy    }
247275970Scy
248275970Scy    /*
249275970Scy     * Make the control device.
250275970Scy     */
251275970Scy    unit = device_get_unit(sc->aac_dev);
252275970Scy    sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644,
253275970Scy			     "aac%d", unit);
254275970Scy    (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
255275970Scy    (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
256275970Scy
257275970Scy    sc->aac_dev_t->si_drv1 = sc;
258275970Scy
259275970Scy    return(0);
260275970Scy}
261275970Scy
262275970Scy/******************************************************************************
263275970Scy * Probe for containers, create disks.
264275970Scy */
265275970Scystatic void
266275970Scyaac_startup(void *arg)
267275970Scy{
268275970Scy    struct aac_softc		*sc = (struct aac_softc *)arg;
269275970Scy    struct aac_mntinfo		mi;
270275970Scy    struct aac_mntinforesponse	mir;
271275970Scy    device_t			child;
272275970Scy    u_int16_t			rsize;
273275970Scy    int				i;
274275970Scy
275275970Scy    debug_called(1);
276275970Scy
277275970Scy    /* disconnect ourselves from the intrhook chain */
278275970Scy    config_intrhook_disestablish(&sc->aac_ich);
279275970Scy
280275970Scy    /* loop over possible containers */
281275970Scy    mi.Command = VM_NameServe;
282275970Scy    mi.MntType = FT_FILESYS;
283275970Scy    for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
284275970Scy	/* request information on this container */
285275970Scy	mi.MntCount = i;
286275970Scy	if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
287275970Scy			 sizeof(struct aac_mntinfo), &mir, &rsize)) {
288275970Scy	    debug(2, "error probing container %d", i);
289275970Scy	    continue;
290275970Scy	}
291275970Scy	/* check response size */
292275970Scy	if (rsize != sizeof(mir)) {
293275970Scy	    debug(2, "container info response wrong size (%d should be %d)",
294275970Scy		  rsize, sizeof(mir));
295275970Scy	    continue;
296275970Scy	}
297275970Scy	/*
298275970Scy	 * Check container volume type for validity.  Note that many of the
299275970Scy	 * possible types may never show up.
300275970Scy	 */
301275970Scy	if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) {
302275970Scy	    debug(1, "%d: id %x  name '%.16s'  size %u  type %d",
303275970Scy		  i, mir.MntTable[0].ObjectId,
304275970Scy		  mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity,
305275970Scy		  mir.MntTable[0].VolType);
306275970Scy
307275970Scy	    if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) {
308275970Scy		device_printf(sc->aac_dev, "device_add_child failed\n");
309275970Scy	    } else {
310275970Scy		device_set_ivars(child, &sc->aac_container[i]);
311275970Scy	    }
312275970Scy	    device_set_desc(child, aac_describe_code(aac_container_types,
313275970Scy			    mir.MntTable[0].VolType));
314275970Scy	    sc->aac_container[i].co_disk = child;
315275970Scy	    sc->aac_container[i].co_mntobj = mir.MntTable[0];
316275970Scy	}
317275970Scy    }
318275970Scy
319275970Scy    /* poke the bus to actually attach the child devices */
320275970Scy    if (bus_generic_attach(sc->aac_dev))
321275970Scy	device_printf(sc->aac_dev, "bus_generic_attach failed\n");
322275970Scy
323275970Scy    /* mark the controller up */
324275970Scy    sc->aac_state &= ~AAC_STATE_SUSPEND;
325275970Scy
326275970Scy    /* enable interrupts now */
327275970Scy    AAC_UNMASK_INTERRUPTS(sc);
328275970Scy
329275970Scy    /* enable the timeout watchdog */
330275970Scy    timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
331275970Scy}
332275970Scy
333275970Scy/******************************************************************************
334275970Scy * Free all of the resources associated with (sc)
335275970Scy *
336275970Scy * Should not be called if the controller is active.
337275970Scy */
338275970Scyvoid
339275970Scyaac_free(struct aac_softc *sc)
340275970Scy{
341275970Scy    debug_called(1);
342275970Scy
343275970Scy    /* remove the control device */
344275970Scy    if (sc->aac_dev_t != NULL)
345275970Scy	destroy_dev(sc->aac_dev_t);
346275970Scy
347275970Scy    /* throw away any FIB buffers, discard the FIB DMA tag */
348275970Scy    if (sc->aac_fibs != NULL)
349275970Scy	aac_free_commands(sc);
350275970Scy    if (sc->aac_fib_dmat)
351275970Scy	bus_dma_tag_destroy(sc->aac_fib_dmat);
352275970Scy
353275970Scy    /* destroy the common area */
354275970Scy    if (sc->aac_common) {
355275970Scy	bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
356275970Scy	bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
357275970Scy			sc->aac_common_dmamap);
358275970Scy    }
359275970Scy    if (sc->aac_common_dmat)
360275970Scy	bus_dma_tag_destroy(sc->aac_common_dmat);
361275970Scy
362275970Scy    /* disconnect the interrupt handler */
363275970Scy    if (sc->aac_intr)
364275970Scy	bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
365275970Scy    if (sc->aac_irq != NULL)
366275970Scy	bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
367275970Scy			     sc->aac_irq);
368275970Scy
369275970Scy    /* destroy data-transfer DMA tag */
370275970Scy    if (sc->aac_buffer_dmat)
371275970Scy	bus_dma_tag_destroy(sc->aac_buffer_dmat);
372275970Scy
373275970Scy    /* destroy the parent DMA tag */
374275970Scy    if (sc->aac_parent_dmat)
375275970Scy	bus_dma_tag_destroy(sc->aac_parent_dmat);
376275970Scy
377275970Scy    /* release the register window mapping */
378275970Scy    if (sc->aac_regs_resource != NULL)
379275970Scy	bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid,
380275970Scy			     sc->aac_regs_resource);
381275970Scy}
382275970Scy
383275970Scy/******************************************************************************
384275970Scy * Disconnect from the controller completely, in preparation for unload.
385275970Scy */
386275970Scyint
387275970Scyaac_detach(device_t dev)
388275970Scy{
389275970Scy    struct aac_softc	*sc = device_get_softc(dev);
390275970Scy    int			error;
391275970Scy
392275970Scy    debug_called(1);
393275970Scy
394275970Scy    if (sc->aac_state & AAC_STATE_OPEN)
395275970Scy	return(EBUSY);
396275970Scy
397275970Scy    if ((error = aac_shutdown(dev)))
398275970Scy	return(error);
399275970Scy
400275970Scy    aac_free(sc);
401275970Scy
402275970Scy    return(0);
403275970Scy}
404275970Scy
405275970Scy/******************************************************************************
406275970Scy * Bring the controller down to a dormant state and detach all child devices.
407275970Scy *
408275970Scy * This function is called before detach or system shutdown.
409275970Scy *
410275970Scy * Note that we can assume that the bioq on the controller is empty, as we won't
411275970Scy * allow shutdown if any device is open.
412275970Scy */
413275970Scyint
414275970Scyaac_shutdown(device_t dev)
415275970Scy{
416275970Scy    struct aac_softc		*sc = device_get_softc(dev);
417275970Scy    struct aac_close_command	cc;
418275970Scy    int				s, i;
419275970Scy
420275970Scy    debug_called(1);
421275970Scy
422275970Scy    s = splbio();
423275970Scy
424275970Scy    sc->aac_state |= AAC_STATE_SUSPEND;
425275970Scy
426275970Scy    /*
427275970Scy     * Send a Container shutdown followed by a HostShutdown FIB to the
428275970Scy     * controller to convince it that we don't want to talk to it anymore.
429275970Scy     * We've been closed and all I/O completed already
430275970Scy     */
431275970Scy    device_printf(sc->aac_dev, "shutting down controller...");
432275970Scy
433275970Scy    cc.Command = VM_CloseAll;
434275970Scy    cc.ContainerId = 0xffffffff;
435275970Scy    if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) {
436275970Scy	printf("FAILED.\n");
437275970Scy    } else {
438275970Scy	i = 0;
439275970Scy	if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i,
440275970Scy			 sizeof(i), NULL, NULL)) {
441275970Scy	    printf("FAILED.\n");
442275970Scy	} else {
443275970Scy	    printf("done.\n");
444275970Scy	}
445275970Scy    }
446275970Scy
447275970Scy    AAC_MASK_INTERRUPTS(sc);
448275970Scy
449275970Scy    splx(s);
450275970Scy    return(0);
451275970Scy}
452275970Scy
453275970Scy/******************************************************************************
454275970Scy * Bring the controller to a quiescent state, ready for system suspend.
455275970Scy */
456275970Scyint
457275970Scyaac_suspend(device_t dev)
458275970Scy{
459275970Scy    struct aac_softc	*sc = device_get_softc(dev);
460275970Scy    int			s;
461275970Scy
462275970Scy    debug_called(1);
463275970Scy    s = splbio();
464275970Scy
465275970Scy    sc->aac_state |= AAC_STATE_SUSPEND;
466275970Scy
467275970Scy    AAC_MASK_INTERRUPTS(sc);
468275970Scy    splx(s);
469275970Scy    return(0);
470275970Scy}
471275970Scy
472275970Scy/******************************************************************************
473275970Scy * Bring the controller back to a state ready for operation.
474275970Scy */
475275970Scyint
476275970Scyaac_resume(device_t dev)
477275970Scy{
478275970Scy    struct aac_softc	*sc = device_get_softc(dev);
479275970Scy
480275970Scy    debug_called(1);
481275970Scy    sc->aac_state &= ~AAC_STATE_SUSPEND;
482275970Scy    AAC_UNMASK_INTERRUPTS(sc);
483275970Scy    return(0);
484275970Scy}
485275970Scy
486275970Scy/******************************************************************************
487275970Scy * Take an interrupt.
488275970Scy */
489275970Scyvoid
490275970Scyaac_intr(void *arg)
491275970Scy{
492275970Scy    struct aac_softc	*sc = (struct aac_softc *)arg;
493275970Scy    u_int16_t		reason;
494275970Scy
495275970Scy    debug_called(2);
496275970Scy
497275970Scy    reason = AAC_GET_ISTATUS(sc);
498275970Scy
499275970Scy    /* controller wants to talk to the log?  XXX should we defer this? */
500275970Scy    if (reason & AAC_DB_PRINTF) {
501275970Scy	if (sc->aac_common->ac_printf[0]) {
502275970Scy	    device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE,
503275970Scy			  sc->aac_common->ac_printf);
504275970Scy	    sc->aac_common->ac_printf[0] = 0;
505275970Scy	}
506275970Scy	AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
507275970Scy	AAC_QNOTIFY(sc, AAC_DB_PRINTF);
508275970Scy    }
509275970Scy
510275970Scy    /* controller has a message for us? */
511275970Scy    if (reason & AAC_DB_COMMAND_READY) {
512275970Scy	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
513275970Scy	aac_host_command(sc);
514275970Scy    }
515275970Scy
516275970Scy    /* controller has a response for us? */
517275970Scy    if (reason & AAC_DB_RESPONSE_READY) {
518275970Scy	AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
519275970Scy	aac_host_response(sc);
520275970Scy    }
521275970Scy
522275970Scy    /*
523275970Scy     * spurious interrupts that we don't use - reset the mask and clear the
524275970Scy     * interrupts
525275970Scy     */
526275970Scy    if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
527275970Scy	AAC_UNMASK_INTERRUPTS(sc);
528275970Scy	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
529275970Scy			  AAC_DB_RESPONSE_NOT_FULL);
530275970Scy    }
531275970Scy};
532275970Scy
533275970Scy/******************************************************************************
534275970Scy ******************************************************************************
535275970Scy				Command Processing
536275970Scy ******************************************************************************
537275970Scy ******************************************************************************/
538275970Scy
539275970Scy/******************************************************************************
540275970Scy * Start as much queued I/O as possible on the controller
541275970Scy */
542275970Scystatic void
543275970Scyaac_startio(struct aac_softc *sc)
544275970Scy{
545275970Scy    struct aac_command	*cm;
546275970Scy
547275970Scy    debug_called(2);
548275970Scy
549275970Scy    for(;;) {
550275970Scy	/* try to get a command that's been put off for lack of resources */
551275970Scy	cm = aac_dequeue_ready(sc);
552293650Sglebius
553275970Scy	/* try to build a command off the bio queue (ignore error return) */
554275970Scy	if (cm == NULL)
555275970Scy	    aac_bio_command(sc, &cm);
556275970Scy
557275970Scy	/* nothing to do? */
558275970Scy	if (cm == NULL)
559275970Scy	    break;
560275970Scy
561275970Scy	/* try to give the command to the controller */
562275970Scy	if (aac_start(cm) == EBUSY) {
563275970Scy	    /* put it on the ready queue for later */
564275970Scy	    aac_requeue_ready(cm);
565275970Scy	    break;
566275970Scy	}
567275970Scy    }
568275970Scy}
569275970Scy
570275970Scy/******************************************************************************
571275970Scy * Deliver a command to the controller; allocate controller resources at the
572275970Scy * last moment when possible.
573275970Scy */
574275970Scystatic int
575275970Scyaac_start(struct aac_command *cm)
576275970Scy{
577275970Scy    struct aac_softc	*sc = cm->cm_sc;
578275970Scy    int			error;
579275970Scy
580275970Scy    debug_called(2);
581275970Scy
582275970Scy    /* get the command mapped */
583275970Scy    aac_map_command(cm);
584275970Scy
585275970Scy    /* fix up the address values in the FIB */
586275970Scy    cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
587275970Scy    cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
588275970Scy
589275970Scy    /* save a pointer to the command for speedy reverse-lookup */
590275970Scy    cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
591275970Scy							 * address issue */
592275970Scy
593275970Scy    /* put the FIB on the outbound queue */
594275970Scy    if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size,
595275970Scy			cm->cm_fib->Header.ReceiverFibAddress)) {
596275970Scy	error = EBUSY;
597275970Scy    } else {
598275970Scy	aac_enqueue_busy(cm);
599275970Scy	error = 0;
600275970Scy    }
601275970Scy    return(error);
602275970Scy}
603275970Scy
604275970Scy/******************************************************************************
605275970Scy * Handle notification of one or more FIBs coming from the controller.
606275970Scy */
607275970Scystatic void
608275970Scyaac_host_command(struct aac_softc *sc)
609275970Scy{
610275970Scy    struct aac_fib	*fib;
611275970Scy    u_int32_t		fib_size;
612275970Scy
613275970Scy    debug_called(1);
614275970Scy
615275970Scy    for (;;) {
616275970Scy	if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib))
617275970Scy	    break;	/* nothing to do */
618275970Scy
619275970Scy	switch(fib->Header.Command) {
620275970Scy	case AifRequest:
621275970Scy	    aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]);
622275970Scy	    break;
623275970Scy	default:
624275970Scy	    device_printf(sc->aac_dev, "unknown command from controller\n");
625275970Scy	    AAC_PRINT_FIB(sc, fib);
626275970Scy	    break;
627275970Scy	}
628275970Scy
629275970Scy	/* XXX reply to FIBs requesting responses ?? */
630275970Scy	/* XXX how do we return these FIBs to the controller? */
631275970Scy    }
632275970Scy}
633275970Scy
634275970Scy/******************************************************************************
635275970Scy * Handle notification of one or more FIBs completed by the controller
636275970Scy */
637275970Scystatic void
638275970Scyaac_host_response(struct aac_softc *sc)
639275970Scy{
640275970Scy    struct aac_command	*cm;
641275970Scy    struct aac_fib	*fib;
642275970Scy    u_int32_t		fib_size;
643275970Scy
644275970Scy    debug_called(2);
645275970Scy
646275970Scy    for (;;) {
647275970Scy	/* look for completed FIBs on our queue */
648275970Scy	if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib))
649275970Scy	    break;	/* nothing to do */
650275970Scy
651275970Scy	/* get the command, unmap and queue for later processing */
652275970Scy	cm = (struct aac_command *)fib->Header.SenderData;
653275970Scy	if (cm == NULL) {
654275970Scy	    AAC_PRINT_FIB(sc, fib);
655275970Scy	} else {
656275970Scy	    aac_remove_busy(cm);
657275970Scy	    aac_unmap_command(cm);		/* XXX defer? */
658275970Scy	    aac_enqueue_complete(cm);
659275970Scy	}
660275970Scy    }
661275970Scy
662275970Scy    /* handle completion processing */
663275970Scy#if __FreeBSD_version >= 500005
664275970Scy    taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
665275970Scy#else
666275970Scy    aac_complete(sc, 0);
667275970Scy#endif
668275970Scy}
669275970Scy
670275970Scy/******************************************************************************
671275970Scy * Process completed commands.
672275970Scy */
673275970Scystatic void
674275970Scyaac_complete(void *context, int pending)
675275970Scy{
676275970Scy    struct aac_softc	*sc = (struct aac_softc *)context;
677275970Scy    struct aac_command	*cm;
678275970Scy
679275970Scy    debug_called(2);
680275970Scy
681275970Scy    /* pull completed commands off the queue */
682275970Scy    for (;;) {
683275970Scy	cm = aac_dequeue_complete(sc);
684275970Scy	if (cm == NULL)
685275970Scy	    break;
686275970Scy	cm->cm_flags |= AAC_CMD_COMPLETED;
687275970Scy
688275970Scy	/* is there a completion handler? */
689275970Scy	if (cm->cm_complete != NULL) {
690275970Scy	    cm->cm_complete(cm);
691275970Scy	} else {
692275970Scy	    /* assume that someone is sleeping on this command */
693275970Scy	    wakeup(cm);
694275970Scy	}
695275970Scy    }
696275970Scy
697275970Scy    /* see if we can start some more I/O */
698275970Scy    aac_startio(sc);
699275970Scy}
700275970Scy
701275970Scy/******************************************************************************
702275970Scy * Handle a bio submitted from a disk device.
703275970Scy */
704275970Scyvoid
705275970Scyaac_submit_bio(struct bio *bp)
706275970Scy{
707275970Scy    struct aac_disk	*ad = (struct aac_disk *)bp->bio_dev->si_drv1;
708275970Scy    struct aac_softc	*sc = ad->ad_controller;
709275970Scy
710275970Scy    debug_called(2);
711275970Scy
712275970Scy    /* queue the BIO and try to get some work done */
713275970Scy    aac_enqueue_bio(sc, bp);
714275970Scy    aac_startio(sc);
715275970Scy}
716275970Scy
717275970Scy/******************************************************************************
718275970Scy * Get a bio and build a command to go with it.
719275970Scy */
720275970Scystatic int
721275970Scyaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
722275970Scy{
723275970Scy    struct aac_command		*cm;
724275970Scy    struct aac_fib		*fib;
725275970Scy    struct aac_blockread	*br;
726275970Scy    struct aac_blockwrite	*bw;
727275970Scy    struct aac_disk		*ad;
728275970Scy    struct bio			*bp;
729275970Scy
730275970Scy    debug_called(2);
731275970Scy
732275970Scy    /* get the resources we will need */
733275970Scy    cm = NULL;
734275970Scy    if ((bp = aac_dequeue_bio(sc)) == NULL)
735275970Scy	goto fail;
736275970Scy    if (aac_alloc_command(sc, &cm))	/* get a command */
737275970Scy	goto fail;
738275970Scy
739275970Scy    /* fill out the command */
740275970Scy    cm->cm_data = (void *)bp->bio_data;
741275970Scy    cm->cm_datalen = bp->bio_bcount;
742275970Scy    cm->cm_complete = aac_bio_complete;
743275970Scy    cm->cm_private = bp;
744275970Scy    cm->cm_timestamp = time_second;
745275970Scy
746275970Scy    /* build the FIB */
747275970Scy    fib = cm->cm_fib;
748275970Scy    fib->Header.XferState =
749275970Scy	AAC_FIBSTATE_HOSTOWNED   |
750275970Scy	AAC_FIBSTATE_INITIALISED |
751275970Scy	AAC_FIBSTATE_FROMHOST    |
752275970Scy	AAC_FIBSTATE_REXPECTED   |
753275970Scy	AAC_FIBSTATE_NORM;
754275970Scy    fib->Header.Command = ContainerCommand;
755275970Scy    fib->Header.Size = sizeof(struct aac_fib_header);
756275970Scy
757275970Scy    /* build the read/write request */
758275970Scy    ad = (struct aac_disk *)bp->bio_dev->si_drv1;
759275970Scy    if (BIO_IS_READ(bp)) {
760275970Scy	br = (struct aac_blockread *)&fib->data[0];
761275970Scy	br->Command = VM_CtBlockRead;
762275970Scy	br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
763275970Scy	br->BlockNumber = bp->bio_pblkno;
764275970Scy	br->ByteCount = bp->bio_bcount;
765275970Scy	fib->Header.Size += sizeof(struct aac_blockread);
766275970Scy	cm->cm_sgtable = &br->SgMap;
767275970Scy	cm->cm_flags |= AAC_CMD_DATAIN;
768275970Scy    } else {
769275970Scy	bw = (struct aac_blockwrite *)&fib->data[0];
770275970Scy	bw->Command = VM_CtBlockWrite;
771275970Scy	bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
772275970Scy	bw->BlockNumber = bp->bio_pblkno;
773275970Scy	bw->ByteCount = bp->bio_bcount;
774275970Scy	bw->Stable = CUNSTABLE;		/* XXX what's appropriate here? */
775275970Scy	fib->Header.Size += sizeof(struct aac_blockwrite);
776275970Scy	cm->cm_flags |= AAC_CMD_DATAOUT;
777275970Scy	cm->cm_sgtable = &bw->SgMap;
778275970Scy    }
779275970Scy
780275970Scy    *cmp = cm;
781275970Scy    return(0);
782275970Scy
783275970Scyfail:
784275970Scy    if (bp != NULL)
785275970Scy	aac_enqueue_bio(sc, bp);
786275970Scy    if (cm != NULL)
787275970Scy	aac_release_command(cm);
788275970Scy    return(ENOMEM);
789275970Scy}
790275970Scy
791275970Scy/******************************************************************************
792275970Scy * Handle a bio-instigated command that has been completed.
793275970Scy */
794275970Scystatic void
795275970Scyaac_bio_complete(struct aac_command *cm)
796275970Scy{
797275970Scy    struct aac_blockread_response	*brr;
798275970Scy    struct aac_blockwrite_response	*bwr;
799275970Scy    struct bio				*bp;
800275970Scy    AAC_FSAStatus			status;
801275970Scy
802275970Scy    /* fetch relevant status and then release the command */
803275970Scy    bp = (struct bio *)cm->cm_private;
804275970Scy    if (BIO_IS_READ(bp)) {
805275970Scy	brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
806275970Scy	status = brr->Status;
807275970Scy    } else {
808275970Scy	bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
809275970Scy	status = bwr->Status;
810275970Scy    }
811275970Scy    aac_release_command(cm);
812275970Scy
813275970Scy    /* fix up the bio based on status */
814275970Scy    if (status == ST_OK) {
815275970Scy	bp->bio_resid = 0;
816275970Scy    } else {
817275970Scy	bp->bio_error = EIO;
818275970Scy	bp->bio_flags |= BIO_ERROR;
819275970Scy	/* pass an error string out to the disk layer */
820275970Scy	bp->bio_driver1 = aac_describe_code(aac_command_status_table, status);
821275970Scy    }
822275970Scy    aac_biodone(bp);
823275970Scy}
824275970Scy
825275970Scy/******************************************************************************
826275970Scy * Submit a command to the controller, return when it completes.
827275970Scy */
828275970Scystatic int
829275970Scyaac_wait_command(struct aac_command *cm, int timeout)
830275970Scy{
831275970Scy    int s, error = 0;
832275970Scy
833275970Scy    debug_called(2);
834275970Scy
835275970Scy    /* Put the command on the ready queue and get things going */
836275970Scy    aac_enqueue_ready(cm);
837275970Scy    aac_startio(cm->cm_sc);
838275970Scy    s = splbio();
839275970Scy    while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
840275970Scy        error = tsleep(cm, PRIBIO, "aacwait", timeout * hz);
841275970Scy    }
842275970Scy    splx(s);
843275970Scy    return(error);
844275970Scy}
845275970Scy
846275970Scy/******************************************************************************
847275970Scy ******************************************************************************
848275970Scy			Command Buffer Management
849275970Scy ******************************************************************************
850275970Scy ******************************************************************************/
851275970Scy
852275970Scy/******************************************************************************
853275970Scy * Allocate a command.
854275970Scy */
855275970Scystatic int
856275970Scyaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
857275970Scy{
858275970Scy    struct aac_command	*cm;
859275970Scy
860275970Scy    debug_called(3);
861275970Scy
862275970Scy    if ((cm = aac_dequeue_free(sc)) == NULL)
863275970Scy	return(ENOMEM);
864275970Scy
865275970Scy    *cmp = cm;
866275970Scy    return(0);
867275970Scy}
868275970Scy
869275970Scy/******************************************************************************
870275970Scy * Release a command back to the freelist.
871275970Scy */
872275970Scystatic void
873275970Scyaac_release_command(struct aac_command *cm)
874275970Scy{
875275970Scy    debug_called(3);
876275970Scy
877275970Scy    /* (re)initialise the command/FIB */
878275970Scy    cm->cm_sgtable = NULL;
879275970Scy    cm->cm_flags = 0;
880275970Scy    cm->cm_complete = NULL;
881275970Scy    cm->cm_private = NULL;
882275970Scy    cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
883275970Scy    cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
884275970Scy    cm->cm_fib->Header.Flags = 0;
885275970Scy    cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
886275970Scy
887275970Scy    /*
888275970Scy     * These are duplicated in aac_start to cover the case where an
889275970Scy     * intermediate stage may have destroyed them.  They're left
890275970Scy     * initialised here for debugging purposes only.
891275970Scy     */
892275970Scy    cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
893275970Scy    cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
894275970Scy
895275970Scy    aac_enqueue_free(cm);
896275970Scy}
897275970Scy
898275970Scy/******************************************************************************
899275970Scy * Map helper for command/FIB allocation.
900275970Scy */
901275970Scystatic void
902275970Scyaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
903275970Scy{
904275970Scy    struct aac_softc	*sc = (struct aac_softc *)arg;
905275970Scy
906275970Scy    debug_called(3);
907275970Scy
908275970Scy    sc->aac_fibphys = segs[0].ds_addr;
909275970Scy}
910275970Scy
911275970Scy/******************************************************************************
912275970Scy * Allocate and initialise commands/FIBs for this adapter.
913 */
914static int
915aac_alloc_commands(struct aac_softc *sc)
916{
917    struct aac_command		*cm;
918    int				i;
919
920    debug_called(1);
921
922    /* allocate the FIBs in DMAable memory and load them */
923    if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
924			 BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
925	return(ENOMEM);
926    }
927    bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
928		    AAC_FIB_COUNT * sizeof(struct aac_fib),
929		    aac_map_command_helper, sc, 0);
930
931    /* initialise constant fields in the command structure */
932    for (i = 0; i < AAC_FIB_COUNT; i++) {
933	cm = &sc->aac_command[i];
934	cm->cm_sc = sc;
935	cm->cm_fib = sc->aac_fibs + i;
936	cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
937
938	if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
939	    aac_release_command(cm);
940    }
941    return(0);
942}
943
944/******************************************************************************
945 * Free FIBs owned by this adapter.
946 */
947static void
948aac_free_commands(struct aac_softc *sc)
949{
950    int			i;
951
952    debug_called(1);
953
954    for (i = 0; i < AAC_FIB_COUNT; i++)
955	bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap);
956    bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
957    bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
958}
959
960/******************************************************************************
961 * Command-mapping helper function - populate this command's s/g table.
962 */
963static void
964aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
965{
966    struct aac_command		*cm = (struct aac_command *)arg;
967    struct aac_fib		*fib = cm->cm_fib;
968    struct aac_sg_table		*sg;
969    int				i;
970
971    debug_called(3);
972
973    /* find the s/g table */
974    sg = cm->cm_sgtable;
975
976    /* copy into the FIB */
977    if (sg != NULL) {
978	sg->SgCount = nseg;
979	for (i = 0; i < nseg; i++) {
980	    sg->SgEntry[i].SgAddress = segs[i].ds_addr;
981	    sg->SgEntry[i].SgByteCount = segs[i].ds_len;
982	}
983	/* update the FIB size for the s/g count */
984	fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
985    }
986
987}
988
989/******************************************************************************
990 * Map a command into controller-visible space.
991 */
992static void
993aac_map_command(struct aac_command *cm)
994{
995    struct aac_softc	*sc = cm->cm_sc;
996
997    debug_called(2);
998
999    /* don't map more than once */
1000    if (cm->cm_flags & AAC_CMD_MAPPED)
1001	return;
1002
1003    if (cm->cm_datalen != 0) {
1004	bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data,
1005			cm->cm_datalen, aac_map_command_sg, cm, 0);
1006
1007	if (cm->cm_flags & AAC_CMD_DATAIN)
1008	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1009			    BUS_DMASYNC_PREREAD);
1010	if (cm->cm_flags & AAC_CMD_DATAOUT)
1011	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1012			    BUS_DMASYNC_PREWRITE);
1013    }
1014    cm->cm_flags |= AAC_CMD_MAPPED;
1015}
1016
1017/******************************************************************************
1018 * Unmap a command from controller-visible space.
1019 */
1020static void
1021aac_unmap_command(struct aac_command *cm)
1022{
1023    struct aac_softc	*sc = cm->cm_sc;
1024
1025    debug_called(2);
1026
1027    if (!(cm->cm_flags & AAC_CMD_MAPPED))
1028	return;
1029
1030    if (cm->cm_datalen != 0) {
1031	if (cm->cm_flags & AAC_CMD_DATAIN)
1032	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1033			    BUS_DMASYNC_POSTREAD);
1034	if (cm->cm_flags & AAC_CMD_DATAOUT)
1035	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1036			    BUS_DMASYNC_POSTWRITE);
1037
1038	bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
1039    }
1040    cm->cm_flags &= ~AAC_CMD_MAPPED;
1041}
1042
1043/******************************************************************************
1044 ******************************************************************************
1045				Hardware Interface
1046 ******************************************************************************
1047 ******************************************************************************/
1048
1049/******************************************************************************
1050 * Initialise the adapter.
1051 */
1052static void
1053aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1054{
1055    struct aac_softc	*sc = (struct aac_softc *)arg;
1056
1057    debug_called(1);
1058
1059    sc->aac_common_busaddr = segs[0].ds_addr;
1060}
1061
1062static int
1063aac_init(struct aac_softc *sc)
1064{
1065    struct aac_adapter_init	*ip;
1066    time_t			then;
1067    u_int32_t			code;
1068    u_int8_t			*qaddr;
1069
1070    debug_called(1);
1071
1072    /*
1073     * First wait for the adapter to come ready.
1074     */
1075    then = time_second;
1076    do {
1077	code = AAC_GET_FWSTATUS(sc);
1078	if (code & AAC_SELF_TEST_FAILED) {
1079	    device_printf(sc->aac_dev, "FATAL: selftest failed\n");
1080	    return(ENXIO);
1081	}
1082	if (code & AAC_KERNEL_PANIC) {
1083	    device_printf(sc->aac_dev, "FATAL: controller kernel panic\n");
1084	    return(ENXIO);
1085	}
1086	if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1087	    device_printf(sc->aac_dev, "FATAL: controller not coming ready, "
1088			  "status %x\n", code);
1089	    return(ENXIO);
1090	}
1091    } while (!(code & AAC_UP_AND_RUNNING));
1092
1093    /*
1094     * Create DMA tag for the common structure and allocate it.
1095     */
1096    if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1097			   1, 0, 			/* algnmnt, boundary */
1098			   BUS_SPACE_MAXADDR,		/* lowaddr */
1099			   BUS_SPACE_MAXADDR, 		/* highaddr */
1100			   NULL, NULL, 			/* filter, filterarg */
1101			   sizeof(struct aac_common), 1,/* maxsize, nsegments */
1102			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1103			   0,				/* flags */
1104			   &sc->aac_common_dmat)) {
1105	device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n");
1106	return(ENOMEM);
1107    }
1108    if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1109			 BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
1110	device_printf(sc->aac_dev, "can't allocate common structure\n");
1111	return(ENOMEM);
1112    }
1113    bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common,
1114		    sizeof(*sc->aac_common), aac_common_map, sc, 0);
1115    bzero(sc->aac_common, sizeof(*sc->aac_common));
1116
1117    /*
1118     * Fill in the init structure.  This tells the adapter about the physical
1119     * location of various important shared data structures.
1120     */
1121    ip = &sc->aac_common->ac_init;
1122    ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1123
1124    ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1125				     offsetof(struct aac_common, ac_fibs);
1126    ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
1127    ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
1128    ip->AdapterFibAlign = sizeof(struct aac_fib);
1129
1130    ip->PrintfBufferAddress = sc->aac_common_busaddr +
1131			      offsetof(struct aac_common, ac_printf);
1132    ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
1133
1134    ip->HostPhysMemPages = 0;			/* not used? */
1135    ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
1136
1137    /*
1138     * Initialise FIB queues.  Note that it appears that the layout of the
1139     * indexes and the segmentation of the entries may be mandated by the
1140     * adapter, which is only told about the base of the queue index fields.
1141     *
1142     * The initial values of the indices are assumed to inform the adapter
1143     * of the sizes of the respective queues, and theoretically it could work
1144     * out the entire layout of the queue structures from this.  We take the
1145     * easy route and just lay this area out like everyone else does.
1146     *
1147     * The Linux driver uses a much more complex scheme whereby several header
1148     * records are kept for each queue.  We use a couple of generic list
1149     * manipulation functions which 'know' the size of each list by virtue of a
1150     * table.
1151     */
1152    qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
1153    qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
1154    sc->aac_queues = (struct aac_queue_table *)qaddr;
1155    ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues
1156			    - (u_int32_t)sc->aac_common);
1157    bzero(sc->aac_queues, sizeof(struct aac_queue_table));
1158
1159    sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1160		AAC_HOST_NORM_CMD_ENTRIES;
1161    sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1162		AAC_HOST_NORM_CMD_ENTRIES;
1163    sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1164		AAC_HOST_HIGH_CMD_ENTRIES;
1165    sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1166		AAC_HOST_HIGH_CMD_ENTRIES;
1167    sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1168		AAC_ADAP_NORM_CMD_ENTRIES;
1169    sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1170		AAC_ADAP_NORM_CMD_ENTRIES;
1171    sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1172		AAC_ADAP_HIGH_CMD_ENTRIES;
1173    sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1174		AAC_ADAP_HIGH_CMD_ENTRIES;
1175    sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1176		AAC_HOST_NORM_RESP_ENTRIES;
1177    sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1178		AAC_HOST_NORM_RESP_ENTRIES;
1179    sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1180		AAC_HOST_HIGH_RESP_ENTRIES;
1181    sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1182		AAC_HOST_HIGH_RESP_ENTRIES;
1183    sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1184		AAC_ADAP_NORM_RESP_ENTRIES;
1185    sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1186		AAC_ADAP_NORM_RESP_ENTRIES;
1187    sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1188		AAC_ADAP_HIGH_RESP_ENTRIES;
1189    sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1190		AAC_ADAP_HIGH_RESP_ENTRIES;
1191    sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1192		&sc->aac_queues->qt_HostNormCmdQueue[0];
1193    sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1194		&sc->aac_queues->qt_HostHighCmdQueue[0];
1195    sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1196		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1197    sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1198		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1199    sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1200		&sc->aac_queues->qt_HostNormRespQueue[0];
1201    sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1202		&sc->aac_queues->qt_HostHighRespQueue[0];
1203    sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1204		&sc->aac_queues->qt_AdapNormRespQueue[0];
1205    sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1206		&sc->aac_queues->qt_AdapHighRespQueue[0];
1207
1208    /*
1209     * Do controller-type-specific initialisation
1210     */
1211    switch (sc->aac_hwif) {
1212    case AAC_HWIF_I960RX:
1213	AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
1214	break;
1215    }
1216
1217    /*
1218     * Give the init structure to the controller.
1219     */
1220    if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1221			 sc->aac_common_busaddr + offsetof(struct aac_common,
1222			 ac_init), 0, 0, 0, NULL)) {
1223	device_printf(sc->aac_dev, "error establishing init structure\n");
1224	return(EIO);
1225    }
1226
1227    return(0);
1228}
1229
1230/******************************************************************************
1231 * Send a synchronous command to the controller and wait for a result.
1232 */
1233static int
1234aac_sync_command(struct aac_softc *sc, u_int32_t command,
1235		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
1236		 u_int32_t *sp)
1237{
1238    time_t	then;
1239    u_int32_t	status;
1240
1241    debug_called(3);
1242
1243    /* populate the mailbox */
1244    AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
1245
1246    /* ensure the sync command doorbell flag is cleared */
1247    AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
1248
1249    /* then set it to signal the adapter */
1250    AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
1251
1252    /* spin waiting for the command to complete */
1253    then = time_second;
1254    do {
1255	if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1256	    debug(2, "timed out");
1257	    return(EIO);
1258	}
1259    } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
1260
1261    /* clear the completion flag */
1262    AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
1263
1264    /* get the command status */
1265    status = AAC_GET_MAILBOXSTATUS(sc);
1266    if (sp != NULL)
1267	*sp = status;
1268    return(0);
1269}
1270
1271/******************************************************************************
1272 * Send a synchronous FIB to the controller and wait for a result.
1273 */
1274static int
1275aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
1276	     void *data, u_int16_t datasize,
1277	     void *result, u_int16_t *resultsize)
1278{
1279    struct aac_fib	*fib = &sc->aac_common->ac_sync_fib;
1280
1281    debug_called(3);
1282
1283    if (datasize > AAC_FIB_DATASIZE)
1284	return(EINVAL);
1285
1286    /*
1287     * Set up the sync FIB
1288     */
1289    fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED |
1290			    AAC_FIBSTATE_EMPTY;
1291    fib->Header.XferState |= xferstate;
1292    fib->Header.Command = command;
1293    fib->Header.StructType = AAC_FIBTYPE_TFIB;
1294    fib->Header.Size = sizeof(struct aac_fib) + datasize;
1295    fib->Header.SenderSize = sizeof(struct aac_fib);
1296    fib->Header.SenderFibAddress = (u_int32_t)fib;
1297    fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
1298				     offsetof(struct aac_common, ac_sync_fib);
1299
1300    /*
1301     * Copy in data.
1302     */
1303    if (data != NULL) {
1304	bcopy(data, fib->data, datasize);
1305	fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM;
1306    }
1307
1308    /*
1309     * Give the FIB to the controller, wait for a response.
1310     */
1311    if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress,
1312			 0, 0, 0, NULL)) {
1313	debug(2, "IO error");
1314	return(EIO);
1315    }
1316
1317    /*
1318     * Copy out the result
1319     */
1320    if (result != NULL) {
1321	*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
1322	bcopy(fib->data, result, *resultsize);
1323    }
1324    return(0);
1325}
1326
1327/********************************************************************************
1328 * Adapter-space FIB queue manipulation
1329 *
1330 * Note that the queue implementation here is a little funky; neither the PI or
1331 * CI will ever be zero.  This behaviour is a controller feature.
1332 */
1333static struct {
1334    int		size;
1335    int		notify;
1336} aac_qinfo[] = {
1337    {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
1338    {AAC_HOST_HIGH_CMD_ENTRIES, 0},
1339    {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
1340    {AAC_ADAP_HIGH_CMD_ENTRIES, 0},
1341    {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
1342    {AAC_HOST_HIGH_RESP_ENTRIES, 0},
1343    {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
1344    {AAC_ADAP_HIGH_RESP_ENTRIES, 0}
1345};
1346
1347/*
1348 * Atomically insert an entry into the nominated queue, returns 0 on success or
1349 * EBUSY if the queue is full.
1350 *
1351 * Note: it would be more efficient to defer notifying the controller in
1352 *       the case where we may be inserting several entries in rapid succession,
1353 *       but implementing this usefully may be difficult (it would involve a
1354 *       separate queue/notify interface).
1355 */
1356static int
1357aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size,
1358		u_int32_t fib_addr)
1359{
1360    u_int32_t	pi, ci;
1361    int		s, error;
1362
1363    debug_called(3);
1364
1365    s = splbio();
1366
1367    /* get the producer/consumer indices */
1368    pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
1369    ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
1370
1371    /* wrap the queue? */
1372    if (pi >= aac_qinfo[queue].size)
1373	pi = 0;
1374
1375    /* check for queue full */
1376    if ((pi + 1) == ci) {
1377	error = EBUSY;
1378	goto out;
1379    }
1380
1381    /* populate queue entry */
1382    (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
1383    (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
1384
1385    /* update producer index */
1386    sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
1387
1388    /* notify the adapter if we know how */
1389    if (aac_qinfo[queue].notify != 0)
1390	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1391
1392    error = 0;
1393
1394out:
1395    splx(s);
1396    return(error);
1397}
1398
1399/*
1400 * Atomically remove one entry from the nominated queue, returns 0 on success or
1401 * ENOENT if the queue is empty.
1402 */
1403static int
1404aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1405		struct aac_fib **fib_addr)
1406{
1407    u_int32_t	pi, ci;
1408    int		s, error;
1409
1410    debug_called(3);
1411
1412    s = splbio();
1413
1414    /* get the producer/consumer indices */
1415    pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
1416    ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
1417
1418    /* check for queue empty */
1419    if (ci == pi) {
1420	error = ENOENT;
1421	goto out;
1422    }
1423
1424    /* wrap the queue? */
1425    if (ci >= aac_qinfo[queue].size)
1426	ci = 0;
1427
1428    /* fetch the entry */
1429    *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
1430    *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr;
1431
1432    /* update consumer index */
1433    sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
1434
1435    /* if we have made the queue un-full, notify the adapter */
1436    if (((pi + 1) == ci) && (aac_qinfo[queue].notify != 0))
1437	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1438    error = 0;
1439
1440out:
1441    splx(s);
1442    return(error);
1443}
1444
1445/******************************************************************************
1446 * Check for commands that have been outstanding for a suspiciously long time,
1447 * and complain about them.
1448 */
1449static void
1450aac_timeout(struct aac_softc *sc)
1451{
1452    int		s;
1453    struct	aac_command *cm;
1454    time_t	deadline;
1455
1456    /* simulate an interrupt to handle possibly-missed interrupts */
1457    aac_intr(sc);
1458
1459    /* kick the I/O queue to restart it in the case of deadlock */
1460    aac_startio(sc);
1461
1462    /* traverse the busy command list, bitch about late commands once only */
1463    deadline = time_second - AAC_CMD_TIMEOUT;
1464    s = splbio();
1465    TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
1466	if ((cm->cm_timestamp < deadline) &&
1467	    !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
1468	    cm->cm_flags |= AAC_CMD_TIMEDOUT;
1469	    device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n",
1470			  (int)(time_second - cm->cm_timestamp));
1471	    AAC_PRINT_FIB(sc, cm->cm_fib);
1472	}
1473    }
1474    splx(s);
1475
1476    /* reset the timer for next time */
1477    timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
1478    return;
1479}
1480
1481/******************************************************************************
1482 ******************************************************************************
1483			Interface Function Vectors
1484 ******************************************************************************
1485 ******************************************************************************/
1486
1487/******************************************************************************
1488 * Read the current firmware status word.
1489 */
1490static int
1491aac_sa_get_fwstatus(struct aac_softc *sc)
1492{
1493    debug_called(3);
1494
1495    return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
1496}
1497
1498static int
1499aac_rx_get_fwstatus(struct aac_softc *sc)
1500{
1501    debug_called(3);
1502
1503    return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
1504}
1505
1506/******************************************************************************
1507 * Notify the controller of a change in a given queue
1508 */
1509
1510static void
1511aac_sa_qnotify(struct aac_softc *sc, int qbit)
1512{
1513    debug_called(3);
1514
1515    AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
1516}
1517
1518static void
1519aac_rx_qnotify(struct aac_softc *sc, int qbit)
1520{
1521    debug_called(3);
1522
1523    AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
1524}
1525
1526/******************************************************************************
1527 * Get the interrupt reason bits
1528 */
1529static int
1530aac_sa_get_istatus(struct aac_softc *sc)
1531{
1532    debug_called(3);
1533
1534    return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
1535}
1536
1537static int
1538aac_rx_get_istatus(struct aac_softc *sc)
1539{
1540    debug_called(3);
1541
1542    return(AAC_GETREG4(sc, AAC_RX_ODBR));
1543}
1544
1545/******************************************************************************
1546 * Clear some interrupt reason bits
1547 */
1548static void
1549aac_sa_clear_istatus(struct aac_softc *sc, int mask)
1550{
1551    debug_called(3);
1552
1553    AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
1554}
1555
1556static void
1557aac_rx_clear_istatus(struct aac_softc *sc, int mask)
1558{
1559    debug_called(3);
1560
1561    AAC_SETREG4(sc, AAC_RX_ODBR, mask);
1562}
1563
1564/******************************************************************************
1565 * Populate the mailbox and set the command word
1566 */
1567static void
1568aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
1569		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
1570{
1571    debug_called(4);
1572
1573    AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
1574    AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
1575    AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
1576    AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
1577    AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
1578}
1579
1580static void
1581aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
1582		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
1583{
1584    debug_called(4);
1585
1586    AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
1587    AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
1588    AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
1589    AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
1590    AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
1591}
1592
1593/******************************************************************************
1594 * Fetch the immediate command status word
1595 */
1596static int
1597aac_sa_get_mailboxstatus(struct aac_softc *sc)
1598{
1599    debug_called(4);
1600
1601    return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
1602}
1603
1604static int
1605aac_rx_get_mailboxstatus(struct aac_softc *sc)
1606{
1607    debug_called(4);
1608
1609    return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
1610}
1611
1612/******************************************************************************
1613 * Set/clear interrupt masks
1614 */
1615static void
1616aac_sa_set_interrupts(struct aac_softc *sc, int enable)
1617{
1618    debug(2, "%sable interrupts", enable ? "en" : "dis");
1619
1620    if (enable) {
1621	AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
1622    } else {
1623	AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
1624    }
1625}
1626
1627static void
1628aac_rx_set_interrupts(struct aac_softc *sc, int enable)
1629{
1630    debug(2, "%sable interrupts", enable ? "en" : "dis");
1631
1632    if (enable) {
1633	AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
1634    } else {
1635	AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
1636    }
1637}
1638
1639/******************************************************************************
1640 ******************************************************************************
1641			Debugging and Diagnostics
1642 ******************************************************************************
1643 ******************************************************************************/
1644
1645/******************************************************************************
1646 * Print some information about the controller.
1647 */
1648static void
1649aac_describe_controller(struct aac_softc *sc)
1650{
1651    u_int8_t			buf[AAC_FIB_DATASIZE];	/* XXX really a bit big
1652							 * for the stack */
1653    u_int16_t			bufsize;
1654    struct aac_adapter_info	*info;
1655    u_int8_t			arg;
1656
1657    debug_called(2);
1658
1659    arg = 0;
1660    if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
1661		     &bufsize)) {
1662	device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1663	return;
1664    }
1665    if (bufsize != sizeof(*info)) {
1666	device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data "
1667		      "size (%d != %d)\n", bufsize, sizeof(*info));
1668	/*return;*/
1669    }
1670    info = (struct aac_adapter_info *)&buf[0];
1671
1672    device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n",
1673		  aac_describe_code(aac_cpu_variant, info->CpuVariant),
1674		  info->ClockSpeed, info->TotalMem / (1024 * 1024),
1675		  aac_describe_code(aac_battery_platform,
1676		  info->batteryPlatform), info->batteryPlatform);
1677
1678    /* save the kernel revision structure for later use */
1679    sc->aac_revision = info->KernelRevision;
1680    device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n",
1681		  info->KernelRevision.external.comp.major,
1682		  info->KernelRevision.external.comp.minor,
1683		  info->KernelRevision.external.comp.dash,
1684		  info->SerialNumber);	/* XXX format? */
1685}
1686
1687/******************************************************************************
1688 * Look up a text description of a numeric error code and return a pointer to
1689 * same.
1690 */
1691static char *
1692aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
1693{
1694    int		i;
1695
1696    for (i = 0; table[i].string != NULL; i++)
1697	if (table[i].code == code)
1698	    return(table[i].string);
1699    return(table[i + 1].string);
1700}
1701
1702/*****************************************************************************
1703 *****************************************************************************
1704				Management Interface
1705 *****************************************************************************
1706 *****************************************************************************/
1707
1708static int
1709aac_open(dev_t dev, int flags, int fmt, struct proc *p)
1710{
1711    struct aac_softc	*sc = dev->si_drv1;
1712
1713    debug_called(2);
1714
1715    /* Check to make sure the device isn't already open */
1716    if (sc->aac_state & AAC_STATE_OPEN) {
1717        return EBUSY;
1718    }
1719    sc->aac_state |= AAC_STATE_OPEN;
1720
1721    return 0;
1722}
1723
1724static int
1725aac_close(dev_t dev, int flags, int fmt, struct proc *p)
1726{
1727    struct aac_softc	*sc = dev->si_drv1;
1728
1729    debug_called(2);
1730
1731    /* Mark this unit as no longer open  */
1732    sc->aac_state &= ~AAC_STATE_OPEN;
1733
1734    return 0;
1735}
1736
1737static int
1738aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
1739{
1740    union aac_statrequest	*as = (union aac_statrequest *)arg;
1741    struct aac_softc		*sc = dev->si_drv1;
1742    int				error = 0;
1743#ifdef AAC_COMPAT_LINUX
1744    int				i;
1745#endif
1746
1747    debug_called(2);
1748
1749    switch (cmd) {
1750    case AACIO_STATS:
1751	switch (as->as_item) {
1752	case AACQ_FREE:
1753	case AACQ_BIO:
1754	case AACQ_READY:
1755	case AACQ_BUSY:
1756	case AACQ_COMPLETE:
1757	    bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
1758		  sizeof(struct aac_qstat));
1759	    break;
1760	default:
1761	    error = ENOENT;
1762	    break;
1763	}
1764	break;
1765
1766#ifdef AAC_COMPAT_LINUX
1767    case FSACTL_SENDFIB:
1768	debug(1, "FSACTL_SENDFIB");
1769	error = aac_ioctl_sendfib(sc, arg);
1770	break;
1771    case FSACTL_AIF_THREAD:
1772	debug(1, "FSACTL_AIF_THREAD");
1773	error = EINVAL;
1774	break;
1775    case FSACTL_OPEN_GET_ADAPTER_FIB:
1776	debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
1777	/*
1778	 * Pass the caller out an AdapterFibContext.
1779	 *
1780	 * Note that because we only support one opener, we
1781	 * basically ignore this.  Set the caller's context to a magic
1782	 * number just in case.
1783	 *
1784	 * The Linux code hands the driver a pointer into kernel space,
1785	 * and then trusts it when the caller hands it back.  Aiee!
1786	 */
1787	i = AAC_AIF_SILLYMAGIC;
1788	error = copyout(&i, arg, sizeof(i));
1789	break;
1790    case FSACTL_GET_NEXT_ADAPTER_FIB:
1791	debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
1792	error = aac_linux_getnext_aif(sc, arg);
1793	break;
1794    case FSACTL_CLOSE_GET_ADAPTER_FIB:
1795	debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
1796	/* don't do anything here */
1797	break;
1798    case FSACTL_MINIPORT_REV_CHECK:
1799	debug(1, "FSACTL_MINIPORT_REV_CHECK");
1800	error = aac_linux_rev_check(sc, arg);
1801	break;
1802#endif
1803    default:
1804	device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd);
1805	error = EINVAL;
1806	break;
1807    }
1808    return(error);
1809}
1810
1811/******************************************************************************
1812 * Send a FIB supplied from userspace
1813 */
1814static int
1815aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
1816{
1817    struct aac_command 	*cm;
1818    int			size, error;
1819
1820    debug_called(2);
1821
1822    cm = NULL;
1823
1824    /*
1825     * Get a command
1826     */
1827    if (aac_alloc_command(sc, &cm)) {
1828	error = EBUSY;
1829	goto out;
1830    }
1831
1832    /*
1833     * Fetch the FIB header, then re-copy to get data as well.
1834     */
1835    if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0)
1836	goto out;
1837    size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
1838    if (size > sizeof(struct aac_fib)) {
1839	device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size,
1840		      sizeof(struct aac_fib));
1841	size = sizeof(struct aac_fib);
1842    }
1843    if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
1844	goto out;
1845    cm->cm_fib->Header.Size = size;
1846
1847    /*
1848     * Pass the FIB to the controller, wait for it to complete.
1849     */
1850    if ((error = aac_wait_command(cm, 30)) != 0)	/* XXX user timeout? */
1851	goto out;
1852
1853    /*
1854     * Copy the FIB and data back out to the caller.
1855     */
1856    size = cm->cm_fib->Header.Size;
1857    if (size > sizeof(struct aac_fib)) {
1858	device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size,
1859		      sizeof(struct aac_fib));
1860	size = sizeof(struct aac_fib);
1861    }
1862    error = copyout(cm->cm_fib, ufib, size);
1863
1864out:
1865    if (cm != NULL)
1866	aac_release_command(cm);
1867    return(error);
1868}
1869
1870/******************************************************************************
1871 * Handle an AIF sent to us by the controller; queue it for later reference.
1872 *
1873 * XXX what's the right thing to do here when the queue is full?  Drop the older
1874 * or newer entries?
1875 */
1876static void
1877aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif)
1878{
1879    int		next, s;
1880
1881    debug_called(2);
1882
1883    s = splbio();
1884    next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
1885    if (next != sc->aac_aifq_tail) {
1886	bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
1887	sc->aac_aifq_head = next;
1888	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
1889	    wakeup(sc->aac_aifq);
1890    }
1891    splx(s);
1892    aac_print_aif(sc, aif);
1893}
1894
1895/******************************************************************************
1896 ******************************************************************************
1897			Linux Management Interface
1898 ******************************************************************************
1899 ******************************************************************************/
1900
1901#ifdef AAC_COMPAT_LINUX
1902
1903#include <sys/proc.h>
1904#include <machine/../linux/linux.h>
1905#include <machine/../linux/linux_proto.h>
1906#include <compat/linux/linux_ioctl.h>
1907
1908#define AAC_LINUX_IOCTL_MIN  0x2000
1909#define AAC_LINUX_IOCTL_MAX  0x21ff
1910
1911static linux_ioctl_function_t aac_linux_ioctl;
1912static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl,
1913						AAC_LINUX_IOCTL_MIN,
1914						AAC_LINUX_IOCTL_MAX};
1915
1916SYSINIT  (aac_register,   SI_SUB_KLD, SI_ORDER_MIDDLE,
1917	  linux_ioctl_register_handler, &aac_handler);
1918SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
1919	  linux_ioctl_unregister_handler, &aac_handler);
1920
1921MODULE_DEPEND(aac, linux, 1, 1, 1);
1922
1923static int
1924aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
1925{
1926    struct file		*fp = p->p_fd->fd_ofiles[args->fd];
1927    u_long		cmd = args->cmd;
1928
1929    /*
1930     * Pass the ioctl off to our standard handler.
1931     */
1932    return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p));
1933}
1934
1935/******************************************************************************
1936 * Return the Revision of the driver to userspace and check to see if the
1937 * userspace app is possibly compatible.  This is extremely bogus right now
1938 * because I have no idea how to handle the versioning of this driver.  It is
1939 * needed, though, to get aaccli working.
1940 */
1941static int
1942aac_linux_rev_check(struct aac_softc *sc, caddr_t udata)
1943{
1944    struct aac_rev_check	rev_check;
1945    struct aac_rev_check_resp	rev_check_resp;
1946    int				error = 0;
1947
1948    debug_called(2);
1949
1950    /*
1951     * Copyin the revision struct from userspace
1952     */
1953    if ((error = copyin(udata, (caddr_t)&rev_check,
1954			sizeof(struct aac_rev_check))) != 0) {
1955	return error;
1956    }
1957
1958    debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber);
1959
1960    /*
1961     * Doctor up the response struct.
1962     */
1963    rev_check_resp.possiblyCompatible = 1;
1964    rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul;
1965    rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber;
1966
1967    return(copyout((caddr_t)&rev_check_resp, udata,
1968		   sizeof(struct aac_rev_check_resp)));
1969}
1970
1971/******************************************************************************
1972 * Pass the caller the next AIF in their queue
1973 */
1974static int
1975aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg)
1976{
1977    struct get_adapter_fib_ioctl	agf;
1978    int					error, s;
1979
1980    debug_called(2);
1981
1982    if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
1983
1984	/*
1985	 * Check the magic number that we gave the caller.
1986	 */
1987	if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) {
1988	    error = EFAULT;
1989	} else {
1990
1991	    s = splbio();
1992	    error = aac_linux_return_aif(sc, agf.AifFib);
1993
1994	    if ((error == EAGAIN) && (agf.Wait)) {
1995		sc->aac_state |= AAC_STATE_AIF_SLEEPER;
1996		while (error == EAGAIN) {
1997		    error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0);
1998		    if (error == 0)
1999			error = aac_linux_return_aif(sc, agf.AifFib);
2000		}
2001		sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
2002	    }
2003	    splx(s);
2004	}
2005    }
2006    return(error);
2007}
2008
2009/******************************************************************************
2010 * Hand the next AIF off the top of the queue out to userspace.
2011 */
2012static int
2013aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr)
2014{
2015    int		error, s;
2016
2017    debug_called(2);
2018
2019    s = splbio();
2020    if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2021	error = EAGAIN;
2022    } else {
2023	error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
2024			sizeof(struct aac_aif_command));
2025	if (!error)
2026	    sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
2027    }
2028    splx(s);
2029    return(error);
2030}
2031
2032
2033#endif /* AAC_COMPAT_LINUX */
2034