aac.c revision 83114
198530Sfenner/*- 217683Spst * Copyright (c) 2000 Michael Smith 339291Sfenner * Copyright (c) 2001 Scott Long 417683Spst * Copyright (c) 2000 BSDi 517683Spst * Copyright (c) 2001 Adaptec, Inc. 617683Spst * All rights reserved. 717683Spst * 817683Spst * Redistribution and use in source and binary forms, with or without 917683Spst * modification, are permitted provided that the following conditions 1017683Spst * are met: 1117683Spst * 1. Redistributions of source code must retain the above copyright 1217683Spst * notice, this list of conditions and the following disclaimer. 1317683Spst * 2. Redistributions in binary form must reproduce the above copyright 1417683Spst * notice, this list of conditions and the following disclaimer in the 1517683Spst * documentation and/or other materials provided with the distribution. 1617683Spst * 1717683Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1817683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1917683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2017683Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2117683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2217683Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2317683Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2417683Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2517683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2617683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2717683Spst * SUCH DAMAGE. 2817683Spst * 2917683Spst * $FreeBSD: head/sys/dev/aac/aac.c 83114 2001-09-05 20:43:02Z scottl $ 3017683Spst */ 3117683Spst 3217683Spst/* 3317683Spst * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3417683Spst */ 3517683Spst 3626175Sfenner#include "opt_aac.h" 3798530Sfenner 3817683Spst/* #include <stddef.h> */ 3917683Spst#include <sys/param.h> 4075107Sfenner#include <sys/systm.h> 4175107Sfenner#include <sys/malloc.h> 4275107Sfenner#include <sys/kernel.h> 4375107Sfenner#include <sys/kthread.h> 4417683Spst#include <sys/sysctl.h> 4517683Spst 4617683Spst#include <dev/aac/aac_compat.h> 4717683Spst 4817683Spst#include <sys/bus.h> 4917683Spst#include <sys/conf.h> 5017683Spst#include <sys/devicestat.h> 5117683Spst#include <sys/disk.h> 5217683Spst#include <sys/file.h> 5317683Spst#include <sys/signalvar.h> 5417683Spst#include <sys/time.h> 5517683Spst#include <sys/eventhandler.h> 5617683Spst 5717683Spst#include <machine/bus_memio.h> 5817683Spst#include <machine/bus.h> 5917683Spst#include <machine/resource.h> 6017683Spst 6117683Spst#include <dev/aac/aacreg.h> 6217683Spst#include <dev/aac/aac_ioctl.h> 6317683Spst#include <dev/aac/aacvar.h> 6417683Spst#include <dev/aac/aac_tables.h> 6598530Sfenner 6698530Sfennerdevclass_t aac_devclass; 6798530Sfenner 6898530Sfennerstatic void aac_startup(void *arg); 6998530Sfennerstatic void aac_add_container(struct aac_softc *sc, 7075107Sfenner struct aac_mntinforesponse *mir, int f); 7175107Sfenner 7275107Sfenner/* Command Processing */ 7317683Spststatic void aac_startio(struct aac_softc *sc); 7417683Spststatic void aac_timeout(struct aac_softc *sc); 7517683Spststatic int aac_start(struct aac_command *cm); 7617683Spststatic void aac_complete(void *context, int pending); 7717683Spststatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7817683Spststatic void aac_bio_complete(struct aac_command *cm); 7917683Spststatic int aac_wait_command(struct aac_command *cm, int timeout); 8017683Spststatic void aac_host_command(struct aac_softc *sc); 8117683Spststatic void aac_host_response(struct aac_softc *sc); 8298530Sfenner 8317683Spst/* Command Buffer Management */ 8498530Sfennerstatic int aac_alloc_command(struct aac_softc *sc, 8598530Sfenner struct aac_command **cmp); 8617683Spststatic void aac_release_command(struct aac_command *cm); 8717683Spststatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 8817683Spst int nseg, int error); 8998530Sfennerstatic int aac_alloc_commands(struct aac_softc *sc); 9098530Sfennerstatic void aac_free_commands(struct aac_softc *sc); 9198530Sfennerstatic void aac_map_command(struct aac_command *cm); 9298530Sfennerstatic void aac_unmap_command(struct aac_command *cm); 9398530Sfenner 9498530Sfenner/* Hardware Interface */ 9598530Sfennerstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 9698530Sfenner int error); 9798530Sfennerstatic int aac_init(struct aac_softc *sc); 9898530Sfennerstatic int aac_sync_command(struct aac_softc *sc, u_int32_t command, 9998530Sfenner u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 10098530Sfenner u_int32_t arg3, u_int32_t *sp); 10198530Sfennerstatic int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 10298530Sfenner u_int32_t xferstate, void *data, 10398530Sfenner u_int16_t datasize, void *result, 10498530Sfenner u_int16_t *resultsize); 10517683Spststatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 10698530Sfenner struct aac_command *cm); 10798530Sfennerstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 10898530Sfenner u_int32_t *fib_size, struct aac_fib **fib_addr); 10998530Sfennerstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 11098530Sfenner struct aac_fib *fib); 11198530Sfenner 11298530Sfenner/* StrongARM interface */ 11398530Sfennerstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 11498530Sfennerstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 11598530Sfennerstatic int aac_sa_get_istatus(struct aac_softc *sc); 11698530Sfennerstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11798530Sfennerstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 11898530Sfenner u_int32_t arg0, u_int32_t arg1, 11998530Sfenner u_int32_t arg2, u_int32_t arg3); 12098530Sfennerstatic int aac_sa_get_mailboxstatus(struct aac_softc *sc); 12117683Spststatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 12298530Sfenner 12398530Sfennerstruct aac_interface aac_sa_interface = { 12498530Sfenner aac_sa_get_fwstatus, 12598530Sfenner aac_sa_qnotify, 12698530Sfenner aac_sa_get_istatus, 12798530Sfenner aac_sa_clear_istatus, 12898530Sfenner aac_sa_set_mailbox, 12998530Sfenner aac_sa_get_mailboxstatus, 13098530Sfenner aac_sa_set_interrupts 13198530Sfenner}; 13298530Sfenner 13398530Sfenner/* i960Rx interface */ 13498530Sfennerstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 13598530Sfennerstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 13698530Sfennerstatic int aac_rx_get_istatus(struct aac_softc *sc); 13798530Sfennerstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13898530Sfennerstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 13998530Sfenner u_int32_t arg0, u_int32_t arg1, 14098530Sfenner u_int32_t arg2, u_int32_t arg3); 14198530Sfennerstatic int aac_rx_get_mailboxstatus(struct aac_softc *sc); 14298530Sfennerstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 14398530Sfenner 14498530Sfennerstruct aac_interface aac_rx_interface = { 14598530Sfenner aac_rx_get_fwstatus, 14698530Sfenner aac_rx_qnotify, 14798530Sfenner aac_rx_get_istatus, 14898530Sfenner aac_rx_clear_istatus, 14998530Sfenner aac_rx_set_mailbox, 15098530Sfenner aac_rx_get_mailboxstatus, 15198530Sfenner aac_rx_set_interrupts 15298530Sfenner}; 15398530Sfenner 15498530Sfenner/* Debugging and Diagnostics */ 15598530Sfennerstatic void aac_describe_controller(struct aac_softc *sc); 15698530Sfennerstatic char *aac_describe_code(struct aac_code_lookup *table, 15798530Sfenner u_int32_t code); 15898530Sfenner 15998530Sfenner/* Management Interface */ 16098530Sfennerstatic d_open_t aac_open; 16198530Sfennerstatic d_close_t aac_close; 16298530Sfennerstatic d_ioctl_t aac_ioctl; 16398530Sfennerstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 16498530Sfennerstatic void aac_handle_aif(struct aac_softc *sc, 16598530Sfenner struct aac_fib *fib); 16698530Sfennerstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 16798530Sfennerstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 16898530Sfennerstatic int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 16998530Sfennerstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 17098530Sfenner 17198530Sfenner#define AAC_CDEV_MAJOR 150 17298530Sfenner 17398530Sfennerstatic struct cdevsw aac_cdevsw = { 17498530Sfenner aac_open, /* open */ 17598530Sfenner aac_close, /* close */ 17698530Sfenner noread, /* read */ 17798530Sfenner nowrite, /* write */ 17898530Sfenner aac_ioctl, /* ioctl */ 17998530Sfenner nopoll, /* poll */ 18098530Sfenner nommap, /* mmap */ 18198530Sfenner nostrategy, /* strategy */ 18298530Sfenner "aac", /* name */ 18398530Sfenner AAC_CDEV_MAJOR, /* major */ 18498530Sfenner nodump, /* dump */ 18598530Sfenner nopsize, /* psize */ 18698530Sfenner 0, /* flags */ 18798530Sfenner#if __FreeBSD_version < 500005 18898530Sfenner -1, /* bmaj */ 18998530Sfenner#endif 19098530Sfenner}; 19198530Sfenner 19298530SfennerMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 19398530Sfenner 19498530Sfenner/* sysctl node */ 19598530SfennerSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 19698530Sfenner 19798530Sfenner/* 19898530Sfenner * Device Interface 19998530Sfenner */ 20098530Sfenner 20198530Sfenner/* 20298530Sfenner * Initialise the controller and softc 20398530Sfenner */ 20498530Sfennerint 20598530Sfenneraac_attach(struct aac_softc *sc) 20698530Sfenner{ 20798530Sfenner int error, unit; 20898530Sfenner 20998530Sfenner debug_called(1); 21098530Sfenner 21198530Sfenner /* 21298530Sfenner * Initialise per-controller queues. 21398530Sfenner */ 21498530Sfenner aac_initq_free(sc); 21598530Sfenner aac_initq_ready(sc); 21698530Sfenner aac_initq_busy(sc); 21798530Sfenner aac_initq_complete(sc); 21898530Sfenner aac_initq_bio(sc); 21998530Sfenner 22098530Sfenner#if __FreeBSD_version >= 500005 22198530Sfenner /* 22298530Sfenner * Initialise command-completion task. 22398530Sfenner */ 22498530Sfenner TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 22598530Sfenner#endif 22698530Sfenner 22798530Sfenner /* disable interrupts before we enable anything */ 22898530Sfenner AAC_MASK_INTERRUPTS(sc); 22998530Sfenner 23098530Sfenner /* mark controller as suspended until we get ourselves organised */ 23198530Sfenner sc->aac_state |= AAC_STATE_SUSPEND; 23298530Sfenner 23398530Sfenner /* 23498530Sfenner * Allocate command structures. 23598530Sfenner */ 23698530Sfenner if ((error = aac_alloc_commands(sc)) != 0) 23798530Sfenner return(error); 23898530Sfenner 23998530Sfenner /* 24098530Sfenner * Initialise the adapter. 24198530Sfenner */ 24298530Sfenner if ((error = aac_init(sc)) != 0) 24398530Sfenner return(error); 24498530Sfenner 24598530Sfenner /* 24698530Sfenner * Print a little information about the controller. 24798530Sfenner */ 24898530Sfenner aac_describe_controller(sc); 24998530Sfenner 25098530Sfenner /* 25198530Sfenner * Register to probe our containers later. 25298530Sfenner */ 25398530Sfenner TAILQ_INIT(&sc->aac_container_tqh); 25498530Sfenner AAC_LOCK_INIT(&sc->aac_container_lock); 25598530Sfenner 25698530Sfenner sc->aac_ich.ich_func = aac_startup; 25798530Sfenner sc->aac_ich.ich_arg = sc; 25898530Sfenner if (config_intrhook_establish(&sc->aac_ich) != 0) { 25998530Sfenner device_printf(sc->aac_dev, 26098530Sfenner "can't establish configuration hook\n"); 26198530Sfenner return(ENXIO); 26298530Sfenner } 26398530Sfenner 26498530Sfenner /* 26598530Sfenner * Make the control device. 26698530Sfenner */ 26798530Sfenner unit = device_get_unit(sc->aac_dev); 26898530Sfenner sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, 26998530Sfenner "aac%d", unit); 27098530Sfenner#if __FreeBSD_version > 500005 27198530Sfenner (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 27298530Sfenner (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 27398530Sfenner#endif 27498530Sfenner sc->aac_dev_t->si_drv1 = sc; 27598530Sfenner 27698530Sfenner /* Create the AIF thread */ 27798530Sfenner#if __FreeBSD_version > 500005 27898530Sfenner if (kthread_create((void(*)(void *))aac_host_command, sc, 27998530Sfenner &sc->aifthread, 0, "aac%daif", unit)) 28098530Sfenner#else 28198530Sfenner if (kthread_create((void(*)(void *))aac_host_command, sc, 28298530Sfenner &sc->aifthread, "aac%daif", unit)) 28398530Sfenner#endif 28498530Sfenner panic("Could not create AIF thread\n"); 28598530Sfenner 28698530Sfenner /* Register the shutdown method to only be called post-dump */ 28798530Sfenner if ((EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, sc->aac_dev, 28898530Sfenner SHUTDOWN_PRI_DEFAULT)) == NULL) 28998530Sfenner device_printf(sc->aac_dev, "shutdown event registration failed\n"); 29098530Sfenner 29198530Sfenner return(0); 29298530Sfenner} 29398530Sfenner 29498530Sfenner/* 29598530Sfenner * Probe for containers, create disks. 29698530Sfenner */ 29798530Sfennerstatic void 29898530Sfenneraac_startup(void *arg) 29998530Sfenner{ 30098530Sfenner struct aac_softc *sc; 30198530Sfenner struct aac_mntinfo mi; 30298530Sfenner struct aac_mntinforesponse mir; 30398530Sfenner u_int16_t rsize; 30498530Sfenner int i = 0; 30598530Sfenner 30698530Sfenner debug_called(1); 30798530Sfenner 30898530Sfenner sc = (struct aac_softc *)arg; 30998530Sfenner 31098530Sfenner /* disconnect ourselves from the intrhook chain */ 31198530Sfenner config_intrhook_disestablish(&sc->aac_ich); 31298530Sfenner 31398530Sfenner /* loop over possible containers */ 31498530Sfenner mi.Command = VM_NameServe; 31598530Sfenner mi.MntType = FT_FILESYS; 31698530Sfenner do { 31798530Sfenner /* request information on this container */ 31898530Sfenner mi.MntCount = i; 31998530Sfenner rsize = sizeof(mir); 32098530Sfenner if (aac_sync_fib(sc, ContainerCommand, 0, &mi, 32198530Sfenner sizeof(struct aac_mntinfo), &mir, &rsize)) { 32298530Sfenner debug(2, "error probing container %d", i); 32398530Sfenner continue; 32498530Sfenner } 32598530Sfenner /* check response size */ 32698530Sfenner if (rsize != sizeof(mir)) { 32798530Sfenner debug(2, "container info response wrong size " 32898530Sfenner "(%d should be %d)", rsize, sizeof(mir)); 32998530Sfenner continue; 33098530Sfenner } 33198530Sfenner 33298530Sfenner aac_add_container(sc, &mir, 0); 33398530Sfenner i++; 33498530Sfenner } while ((i < mir.MntRespCount) && (i < AAC_MAX_CONTAINERS)); 33598530Sfenner 33698530Sfenner /* poke the bus to actually attach the child devices */ 33798530Sfenner if (bus_generic_attach(sc->aac_dev)) 33898530Sfenner device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 33998530Sfenner 34098530Sfenner /* mark the controller up */ 34198530Sfenner sc->aac_state &= ~AAC_STATE_SUSPEND; 34298530Sfenner 34398530Sfenner /* enable interrupts now */ 34498530Sfenner AAC_UNMASK_INTERRUPTS(sc); 34598530Sfenner 34698530Sfenner /* enable the timeout watchdog */ 34798530Sfenner timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 34898530Sfenner} 34998530Sfenner 35098530Sfenner/* 35198530Sfenner * Create a device to respresent a new container 35298530Sfenner */ 35398530Sfennerstatic void 35498530Sfenneraac_add_container(struct aac_softc *sc, struct aac_mntinforesponse *mir, int f) 35598530Sfenner{ 35698530Sfenner struct aac_container *co; 35798530Sfenner device_t child; 35898530Sfenner 35998530Sfenner /* 36098530Sfenner * Check container volume type for validity. Note that many of 36198530Sfenner * the possible types may never show up. 36298530Sfenner */ 36398530Sfenner if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 36498530Sfenner MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF, 36598530Sfenner M_NOWAIT); 36698530Sfenner if (co == NULL) 36798530Sfenner panic("Out of memory?!\n"); 36898530Sfenner debug(1, "id %x name '%.16s' size %u type %d", 36998530Sfenner mir->MntTable[0].ObjectId, 37098530Sfenner mir->MntTable[0].FileSystemName, 37198530Sfenner mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 37298530Sfenner 37398530Sfenner if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) 37498530Sfenner device_printf(sc->aac_dev, "device_add_child failed\n"); 37598530Sfenner else 37698530Sfenner device_set_ivars(child, co); 37798530Sfenner device_set_desc(child, aac_describe_code(aac_container_types, 37898530Sfenner mir->MntTable[0].VolType)); 37998530Sfenner co->co_disk = child; 38098530Sfenner co->co_found = f; 38198530Sfenner bcopy(&mir->MntTable[0], &co->co_mntobj, 38298530Sfenner sizeof(struct aac_mntobj)); 38398530Sfenner AAC_LOCK_AQUIRE(&sc->aac_container_lock); 38498530Sfenner TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 38598530Sfenner AAC_LOCK_RELEASE(&sc->aac_container_lock); 38698530Sfenner } 38798530Sfenner} 38898530Sfenner 38998530Sfenner/* 39098530Sfenner * Free all of the resources associated with (sc) 39198530Sfenner * 39298530Sfenner * Should not be called if the controller is active. 39398530Sfenner */ 39498530Sfennervoid 39598530Sfenneraac_free(struct aac_softc *sc) 39698530Sfenner{ 39798530Sfenner debug_called(1); 39898530Sfenner 39998530Sfenner /* remove the control device */ 40098530Sfenner if (sc->aac_dev_t != NULL) 40198530Sfenner destroy_dev(sc->aac_dev_t); 40298530Sfenner 40398530Sfenner /* throw away any FIB buffers, discard the FIB DMA tag */ 40498530Sfenner if (sc->aac_fibs != NULL) 40598530Sfenner aac_free_commands(sc); 40698530Sfenner if (sc->aac_fib_dmat) 40798530Sfenner bus_dma_tag_destroy(sc->aac_fib_dmat); 40898530Sfenner 40998530Sfenner /* destroy the common area */ 41098530Sfenner if (sc->aac_common) { 41198530Sfenner bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 41298530Sfenner bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 41398530Sfenner sc->aac_common_dmamap); 41498530Sfenner } 41598530Sfenner if (sc->aac_common_dmat) 41698530Sfenner bus_dma_tag_destroy(sc->aac_common_dmat); 41798530Sfenner 41898530Sfenner /* disconnect the interrupt handler */ 41998530Sfenner if (sc->aac_intr) 42098530Sfenner bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 42198530Sfenner if (sc->aac_irq != NULL) 42298530Sfenner bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 42398530Sfenner sc->aac_irq); 42498530Sfenner 42598530Sfenner /* destroy data-transfer DMA tag */ 42698530Sfenner if (sc->aac_buffer_dmat) 42798530Sfenner bus_dma_tag_destroy(sc->aac_buffer_dmat); 42898530Sfenner 42998530Sfenner /* destroy the parent DMA tag */ 43098530Sfenner if (sc->aac_parent_dmat) 43198530Sfenner bus_dma_tag_destroy(sc->aac_parent_dmat); 43298530Sfenner 43398530Sfenner /* release the register window mapping */ 43498530Sfenner if (sc->aac_regs_resource != NULL) 43598530Sfenner bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 43698530Sfenner sc->aac_regs_rid, sc->aac_regs_resource); 43798530Sfenner} 43898530Sfenner 43998530Sfenner/* 44098530Sfenner * Disconnect from the controller completely, in preparation for unload. 44198530Sfenner */ 44298530Sfennerint 44398530Sfenneraac_detach(device_t dev) 44498530Sfenner{ 44598530Sfenner struct aac_softc *sc; 44698530Sfenner#if AAC_BROKEN 44798530Sfenner int error; 44898530Sfenner#endif 44998530Sfenner 45075107Sfenner debug_called(1); 45198530Sfenner 45298530Sfenner sc = device_get_softc(dev); 45398530Sfenner 45498530Sfenner if (sc->aac_state & AAC_STATE_OPEN) 45598530Sfenner return(EBUSY); 45698530Sfenner 45798530Sfenner#if AAC_BROKEN 45875107Sfenner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 45998530Sfenner sc->aifflags |= AAC_AIFFLAGS_EXIT; 46098530Sfenner wakeup(sc->aifthread); 46198530Sfenner tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 46298530Sfenner } 46398530Sfenner 46498530Sfenner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 46598530Sfenner panic("Cannot shutdown AIF thread\n"); 46698530Sfenner 46798530Sfenner if ((error = aac_shutdown(dev))) 46898530Sfenner return(error); 46998530Sfenner 47098530Sfenner aac_free(sc); 47198530Sfenner 47298530Sfenner return(0); 47375107Sfenner#else 47475107Sfenner return (EBUSY); 47575107Sfenner#endif 47698530Sfenner} 47775107Sfenner 47898530Sfenner/* 47998530Sfenner * Bring the controller down to a dormant state and detach all child devices. 48098530Sfenner * 48198530Sfenner * This function is called before detach or system shutdown. 48298530Sfenner * 48398530Sfenner * Note that we can assume that the bioq on the controller is empty, as we won't 48498530Sfenner * allow shutdown if any device is open. 48598530Sfenner */ 48698530Sfennerint 48798530Sfenneraac_shutdown(device_t dev) 48875107Sfenner{ 48998530Sfenner struct aac_softc *sc; 49098530Sfenner struct aac_close_command cc; 49198530Sfenner int s, i; 49298530Sfenner 49398530Sfenner debug_called(1); 49498530Sfenner 49598530Sfenner sc = device_get_softc(dev); 49698530Sfenner 49798530Sfenner s = splbio(); 49898530Sfenner 49998530Sfenner sc->aac_state |= AAC_STATE_SUSPEND; 50098530Sfenner 50198530Sfenner /* 50298530Sfenner * Send a Container shutdown followed by a HostShutdown FIB to the 50398530Sfenner * controller to convince it that we don't want to talk to it anymore. 50475107Sfenner * We've been closed and all I/O completed already 50598530Sfenner */ 50698530Sfenner device_printf(sc->aac_dev, "shutting down controller..."); 50798530Sfenner 50898530Sfenner cc.Command = VM_CloseAll; 50998530Sfenner cc.ContainerId = 0xffffffff; 51098530Sfenner if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) 51198530Sfenner printf("FAILED.\n"); 51298530Sfenner else { 51398530Sfenner i = 0; 51498530Sfenner /* 51598530Sfenner * XXX Issuing this command to the controller makes it shut down 51698530Sfenner * but also keeps it from coming back up without a reset of the 51798530Sfenner * PCI bus. This is not desirable if you are just unloading the 51898530Sfenner * driver module with the intent to reload it later. 51998530Sfenner */ 52098530Sfenner if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i, 52198530Sfenner sizeof(i), NULL, NULL)) { 52298530Sfenner printf("FAILED.\n"); 52398530Sfenner } else { 52498530Sfenner printf("done.\n"); 52598530Sfenner } 52698530Sfenner } 52798530Sfenner 52898530Sfenner AAC_MASK_INTERRUPTS(sc); 52998530Sfenner 53098530Sfenner splx(s); 53198530Sfenner return(0); 53298530Sfenner} 53398530Sfenner 53498530Sfenner/* 53598530Sfenner * Bring the controller to a quiescent state, ready for system suspend. 53698530Sfenner */ 53798530Sfennerint 53898530Sfenneraac_suspend(device_t dev) 53998530Sfenner{ 54098530Sfenner struct aac_softc *sc; 54198530Sfenner int s; 54298530Sfenner 54398530Sfenner debug_called(1); 54498530Sfenner 54598530Sfenner sc = device_get_softc(dev); 54698530Sfenner 54798530Sfenner s = splbio(); 54898530Sfenner 54998530Sfenner sc->aac_state |= AAC_STATE_SUSPEND; 55098530Sfenner 55198530Sfenner AAC_MASK_INTERRUPTS(sc); 55298530Sfenner splx(s); 55398530Sfenner return(0); 55498530Sfenner} 55598530Sfenner 55698530Sfenner/* 55798530Sfenner * Bring the controller back to a state ready for operation. 55898530Sfenner */ 55998530Sfennerint 56098530Sfenneraac_resume(device_t dev) 56198530Sfenner{ 56298530Sfenner struct aac_softc *sc; 56398530Sfenner 56498530Sfenner debug_called(1); 56598530Sfenner 56698530Sfenner sc = device_get_softc(dev); 56798530Sfenner 56898530Sfenner sc->aac_state &= ~AAC_STATE_SUSPEND; 56998530Sfenner AAC_UNMASK_INTERRUPTS(sc); 57098530Sfenner return(0); 57198530Sfenner} 57298530Sfenner 57398530Sfenner/* 57498530Sfenner * Take an interrupt. 57598530Sfenner */ 57698530Sfennervoid 57775107Sfenneraac_intr(void *arg) 57875107Sfenner{ 57998530Sfenner struct aac_softc *sc; 58098530Sfenner u_int16_t reason; 58198530Sfenner 58298530Sfenner debug_called(2); 58398530Sfenner 58498530Sfenner sc = (struct aac_softc *)arg; 58598530Sfenner 58698530Sfenner reason = AAC_GET_ISTATUS(sc); 58798530Sfenner 58898530Sfenner /* controller wants to talk to the log? Defer it to the AIF thread */ 58998530Sfenner if (reason & AAC_DB_PRINTF) { 59098530Sfenner AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF); 59198530Sfenner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 59298530Sfenner sc->aifflags |= AAC_AIFFLAGS_PENDING; 59398530Sfenner wakeup(sc->aifthread); 59498530Sfenner } else 59598530Sfenner aac_print_printf(sc); 59698530Sfenner } 59798530Sfenner 59898530Sfenner /* controller has a message for us? */ 59998530Sfenner if (reason & AAC_DB_COMMAND_READY) { 60098530Sfenner AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY); 60198530Sfenner /* XXX What happens if the thread is already awake? */ 60298530Sfenner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 60398530Sfenner sc->aifflags |= AAC_AIFFLAGS_PENDING; 60498530Sfenner wakeup(sc->aifthread); 60598530Sfenner } 60698530Sfenner } 60798530Sfenner 60898530Sfenner /* controller has a response for us? */ 60998530Sfenner if (reason & AAC_DB_RESPONSE_READY) { 61098530Sfenner AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 61198530Sfenner aac_host_response(sc); 61298530Sfenner } 61398530Sfenner 61498530Sfenner /* 61598530Sfenner * spurious interrupts that we don't use - reset the mask and clear the 61698530Sfenner * interrupts 61798530Sfenner */ 61898530Sfenner if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) { 61998530Sfenner AAC_UNMASK_INTERRUPTS(sc); 62098530Sfenner AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL | 62198530Sfenner AAC_DB_RESPONSE_NOT_FULL); 62298530Sfenner } 62398530Sfenner}; 62498530Sfenner 62598530Sfenner/* 62698530Sfenner * Command Processing 62798530Sfenner */ 62898530Sfenner 62998530Sfenner/* 63098530Sfenner * Start as much queued I/O as possible on the controller 63198530Sfenner */ 63298530Sfennerstatic void 63398530Sfenneraac_startio(struct aac_softc *sc) 63498530Sfenner{ 63598530Sfenner struct aac_command *cm; 63698530Sfenner 63798530Sfenner debug_called(2); 63898530Sfenner 63975107Sfenner for (;;) { 64075107Sfenner /* 64198530Sfenner * Try to get a command that's been put off for lack of 64298530Sfenner * resources 64398530Sfenner */ 64498530Sfenner cm = aac_dequeue_ready(sc); 64598530Sfenner 64698530Sfenner /* 64798530Sfenner * Try to build a command off the bio queue (ignore error 64898530Sfenner * return) 64998530Sfenner */ 65098530Sfenner if (cm == NULL) 65175107Sfenner aac_bio_command(sc, &cm); 65298530Sfenner 65398530Sfenner /* nothing to do? */ 65498530Sfenner if (cm == NULL) 65598530Sfenner break; 65698530Sfenner 65798530Sfenner /* try to give the command to the controller */ 65898530Sfenner if (aac_start(cm) == EBUSY) { 65998530Sfenner /* put it on the ready queue for later */ 66098530Sfenner aac_requeue_ready(cm); 66198530Sfenner break; 66298530Sfenner } 66375107Sfenner } 66475107Sfenner} 66575107Sfenner 66698530Sfenner/* 66798530Sfenner * Deliver a command to the controller; allocate controller resources at the 66898530Sfenner * last moment when possible. 66998530Sfenner */ 67098530Sfennerstatic int 67198530Sfenneraac_start(struct aac_command *cm) 67298530Sfenner{ 67398530Sfenner struct aac_softc *sc; 67498530Sfenner int error; 67598530Sfenner 67698530Sfenner debug_called(2); 67798530Sfenner 67817683Spst sc = cm->cm_sc; 67998530Sfenner 68056889Sfenner /* get the command mapped */ 68198530Sfenner aac_map_command(cm); 68298530Sfenner 68398530Sfenner /* fix up the address values in the FIB */ 68417683Spst cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 68598530Sfenner cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 68698530Sfenner 68798530Sfenner /* save a pointer to the command for speedy reverse-lookup */ 68817683Spst cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 68917683Spst * address issue */ 69075107Sfenner 69175107Sfenner /* put the FIB on the outbound queue */ 69298530Sfenner error = aac_enqueue_fib(sc, cm->cm_queue, cm); 69317683Spst return(error); 69417683Spst} 69598530Sfenner 69698530Sfenner/* 69798530Sfenner * Handle notification of one or more FIBs coming from the controller. 69898530Sfenner */ 69998530Sfennerstatic void 70098530Sfenneraac_host_command(struct aac_softc *sc) 70156889Sfenner{ 70256889Sfenner struct aac_fib *fib; 70398530Sfenner u_int32_t fib_size; 70456889Sfenner int size; 70575107Sfenner 70698530Sfenner debug_called(2); 70798530Sfenner 70898530Sfenner sc->aifflags |= AAC_AIFFLAGS_RUNNING; 70956889Sfenner 71056889Sfenner while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 71156889Sfenner if (!(sc->aifflags & AAC_AIFFLAGS_PENDING)) 71256889Sfenner tsleep(sc->aifthread, PRIBIO, "aifthd", 15 * hz); 71398530Sfenner 71475107Sfenner sc->aifflags &= ~AAC_AIFFLAGS_PENDING; 71575107Sfenner for (;;) { 71675107Sfenner if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 71775107Sfenner &fib_size, &fib)) 71856889Sfenner break; /* nothing to do */ 71998530Sfenner 72098530Sfenner AAC_PRINT_FIB(sc, fib); 72156889Sfenner 72256889Sfenner switch (fib->Header.Command) { 72356889Sfenner case AifRequest: 72498530Sfenner aac_handle_aif(sc, fib); 72556889Sfenner break; 72617683Spst default: 72717683Spst device_printf(sc->aac_dev, "unknown command " 72856889Sfenner "from controller\n"); 72956889Sfenner break; 73056889Sfenner } 73117683Spst 73298530Sfenner /* Return the AIF to the controller. */ 73317683Spst if ((fib->Header.XferState == 0) || 73417683Spst (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 73517683Spst break; 73617683Spst 73798530Sfenner if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 73817683Spst fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 73998530Sfenner *(AAC_FSAStatus*)fib->data = ST_OK; 74098530Sfenner 74117683Spst /* XXX Compute the Size field? */ 74298530Sfenner size = fib->Header.Size; 74398530Sfenner if (size > sizeof(struct aac_fib)) { 74498530Sfenner size = sizeof(struct aac_fib); 74526175Sfenner fib->Header.Size = size; 74626175Sfenner } 74775107Sfenner /* 74875107Sfenner * Since we did not generate this command, it 74998530Sfenner * cannot go through the normal 75098530Sfenner * enqueue->startio chain. 75117683Spst */ 75298530Sfenner aac_enqueue_response(sc, 75398530Sfenner AAC_ADAP_NORM_RESP_QUEUE, 75417683Spst fib); 75598530Sfenner } 75617683Spst } 75717683Spst aac_print_printf(sc); 75898530Sfenner 75998530Sfenner } 76098530Sfenner sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 76198530Sfenner wakeup(sc->aac_dev); 76298530Sfenner 76398530Sfenner#if __FreeBSD_version > 500005 76498530Sfenner mtx_lock(&Giant); 76598530Sfenner#endif 76698530Sfenner kthread_exit(0); 76798530Sfenner} 76898530Sfenner 76998530Sfenner/* 77098530Sfenner * Handle notification of one or more FIBs completed by the controller 77198530Sfenner */ 77298530Sfennerstatic void 77398530Sfenneraac_host_response(struct aac_softc *sc) 77498530Sfenner{ 77598530Sfenner struct aac_command *cm; 77698530Sfenner struct aac_fib *fib; 77798530Sfenner u_int32_t fib_size; 77898530Sfenner 77998530Sfenner debug_called(2); 78098530Sfenner 78198530Sfenner for (;;) { 78298530Sfenner /* look for completed FIBs on our queue */ 78398530Sfenner if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 78498530Sfenner &fib)) 78598530Sfenner break; /* nothing to do */ 78698530Sfenner 78798530Sfenner /* get the command, unmap and queue for later processing */ 78898530Sfenner cm = (struct aac_command *)fib->Header.SenderData; 78998530Sfenner if (cm == NULL) { 79098530Sfenner AAC_PRINT_FIB(sc, fib); 79198530Sfenner } else { 79298530Sfenner aac_remove_busy(cm); 79398530Sfenner aac_unmap_command(cm); /* XXX defer? */ 79498530Sfenner aac_enqueue_complete(cm); 79598530Sfenner } 79698530Sfenner } 79798530Sfenner 79898530Sfenner /* handle completion processing */ 79998530Sfenner#if __FreeBSD_version >= 500005 80098530Sfenner taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 80198530Sfenner#else 80298530Sfenner aac_complete(sc, 0); 80398530Sfenner#endif 80498530Sfenner} 80598530Sfenner 80698530Sfenner/* 80798530Sfenner * Process completed commands. 80898530Sfenner */ 80998530Sfennerstatic void 81075107Sfenneraac_complete(void *context, int pending) 81198530Sfenner{ 81298530Sfenner struct aac_softc *sc; 81398530Sfenner struct aac_command *cm; 81498530Sfenner 81598530Sfenner debug_called(2); 81675107Sfenner 81798530Sfenner sc = (struct aac_softc *)context; 81898530Sfenner 81998530Sfenner /* pull completed commands off the queue */ 82098530Sfenner for (;;) { 82198530Sfenner cm = aac_dequeue_complete(sc); 82298530Sfenner if (cm == NULL) 82398530Sfenner break; 82498530Sfenner cm->cm_flags |= AAC_CMD_COMPLETED; 82598530Sfenner 82698530Sfenner /* is there a completion handler? */ 82798530Sfenner if (cm->cm_complete != NULL) { 82898530Sfenner cm->cm_complete(cm); 82998530Sfenner } else { 83098530Sfenner /* assume that someone is sleeping on this command */ 83198530Sfenner wakeup(cm); 83298530Sfenner } 83398530Sfenner } 83498530Sfenner 83598530Sfenner /* see if we can start some more I/O */ 83698530Sfenner aac_startio(sc); 83798530Sfenner} 83898530Sfenner 83998530Sfenner/* 84098530Sfenner * Handle a bio submitted from a disk device. 84198530Sfenner */ 84298530Sfennervoid 84398530Sfenneraac_submit_bio(struct bio *bp) 84498530Sfenner{ 84598530Sfenner struct aac_disk *ad; 84698530Sfenner struct aac_softc *sc; 84798530Sfenner 84898530Sfenner debug_called(2); 84998530Sfenner 85098530Sfenner ad = (struct aac_disk *)bp->bio_dev->si_drv1; 85198530Sfenner sc = ad->ad_controller; 85298530Sfenner 85398530Sfenner /* queue the BIO and try to get some work done */ 85498530Sfenner aac_enqueue_bio(sc, bp); 85598530Sfenner aac_startio(sc); 85617683Spst} 85717683Spst 85898530Sfenner/* 85998530Sfenner * Get a bio and build a command to go with it. 86098530Sfenner */ 86198530Sfennerstatic int 86298530Sfenneraac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 86398530Sfenner{ 86498530Sfenner struct aac_command *cm; 86598530Sfenner struct aac_fib *fib; 86698530Sfenner struct aac_blockread *br; 86798530Sfenner struct aac_blockwrite *bw; 86898530Sfenner struct aac_disk *ad; 86998530Sfenner struct bio *bp; 87098530Sfenner 87198530Sfenner debug_called(2); 87298530Sfenner 87317683Spst /* get the resources we will need */ 87498530Sfenner cm = NULL; 87598530Sfenner if ((bp = aac_dequeue_bio(sc)) == NULL) 87698530Sfenner goto fail; 87798530Sfenner if (aac_alloc_command(sc, &cm)) /* get a command */ 87898530Sfenner goto fail; 87998530Sfenner 88098530Sfenner /* fill out the command */ 88198530Sfenner cm->cm_data = (void *)bp->bio_data; 88298530Sfenner cm->cm_datalen = bp->bio_bcount; 88398530Sfenner cm->cm_complete = aac_bio_complete; 88498530Sfenner cm->cm_private = bp; 88598530Sfenner cm->cm_timestamp = time_second; 88698530Sfenner cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 88798530Sfenner 88898530Sfenner /* build the FIB */ 88998530Sfenner fib = cm->cm_fib; 89098530Sfenner fib->Header.XferState = 89198530Sfenner AAC_FIBSTATE_HOSTOWNED | 89298530Sfenner AAC_FIBSTATE_INITIALISED | 89398530Sfenner AAC_FIBSTATE_FROMHOST | 89498530Sfenner AAC_FIBSTATE_REXPECTED | 89598530Sfenner AAC_FIBSTATE_NORM; 89698530Sfenner fib->Header.Command = ContainerCommand; 89798530Sfenner fib->Header.Size = sizeof(struct aac_fib_header); 89898530Sfenner 89998530Sfenner /* build the read/write request */ 90098530Sfenner ad = (struct aac_disk *)bp->bio_dev->si_drv1; 90198530Sfenner if (BIO_IS_READ(bp)) { 90298530Sfenner br = (struct aac_blockread *)&fib->data[0]; 90398530Sfenner br->Command = VM_CtBlockRead; 90498530Sfenner br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 90598530Sfenner br->BlockNumber = bp->bio_pblkno; 90698530Sfenner br->ByteCount = bp->bio_bcount; 90798530Sfenner fib->Header.Size += sizeof(struct aac_blockread); 90898530Sfenner cm->cm_sgtable = &br->SgMap; 90998530Sfenner cm->cm_flags |= AAC_CMD_DATAIN; 91098530Sfenner } else { 91198530Sfenner bw = (struct aac_blockwrite *)&fib->data[0]; 91298530Sfenner bw->Command = VM_CtBlockWrite; 91398530Sfenner bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 91498530Sfenner bw->BlockNumber = bp->bio_pblkno; 91598530Sfenner bw->ByteCount = bp->bio_bcount; 91698530Sfenner bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 91798530Sfenner fib->Header.Size += sizeof(struct aac_blockwrite); 91898530Sfenner cm->cm_flags |= AAC_CMD_DATAOUT; 91998530Sfenner cm->cm_sgtable = &bw->SgMap; 92098530Sfenner } 92198530Sfenner 92298530Sfenner *cmp = cm; 92398530Sfenner return(0); 92498530Sfenner 92598530Sfennerfail: 92698530Sfenner if (bp != NULL) 92798530Sfenner aac_enqueue_bio(sc, bp); 92898530Sfenner if (cm != NULL) 92998530Sfenner aac_release_command(cm); 93098530Sfenner return(ENOMEM); 93198530Sfenner} 93298530Sfenner 93398530Sfenner/* 93498530Sfenner * Handle a bio-instigated command that has been completed. 93598530Sfenner */ 93698530Sfennerstatic void 93798530Sfenneraac_bio_complete(struct aac_command *cm) 93898530Sfenner{ 93998530Sfenner struct aac_blockread_response *brr; 94098530Sfenner struct aac_blockwrite_response *bwr; 94198530Sfenner struct bio *bp; 94298530Sfenner AAC_FSAStatus status; 94398530Sfenner 94498530Sfenner /* fetch relevant status and then release the command */ 94598530Sfenner bp = (struct bio *)cm->cm_private; 94698530Sfenner if (BIO_IS_READ(bp)) { 94798530Sfenner brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 94898530Sfenner status = brr->Status; 94998530Sfenner } else { 95098530Sfenner bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 95198530Sfenner status = bwr->Status; 95298530Sfenner } 95398530Sfenner aac_release_command(cm); 95498530Sfenner 95598530Sfenner /* fix up the bio based on status */ 95698530Sfenner if (status == ST_OK) { 95798530Sfenner bp->bio_resid = 0; 95898530Sfenner } else { 95998530Sfenner bp->bio_error = EIO; 96098530Sfenner bp->bio_flags |= BIO_ERROR; 96198530Sfenner /* pass an error string out to the disk layer */ 96298530Sfenner bp->bio_driver1 = aac_describe_code(aac_command_status_table, 96398530Sfenner status); 96498530Sfenner } 96598530Sfenner aac_biodone(bp); 96698530Sfenner} 96798530Sfenner 96898530Sfenner/* 96998530Sfenner * Dump a block of data to the controller. If the queue is full, tell the 97098530Sfenner * caller to hold off and wait for the queue to drain. 97198530Sfenner */ 97298530Sfennerint 97398530Sfenneraac_dump_enqueue(struct aac_disk *ad, u_int32_t lba, void *data, int dumppages) 97498530Sfenner{ 97598530Sfenner struct aac_softc *sc; 97698530Sfenner struct aac_command *cm; 97798530Sfenner struct aac_fib *fib; 97898530Sfenner struct aac_blockwrite *bw; 97998530Sfenner 98098530Sfenner sc = ad->ad_controller; 98175107Sfenner cm = NULL; 98275107Sfenner 98398530Sfenner if (aac_alloc_command(sc, &cm)) 98498530Sfenner return (EBUSY); 98598530Sfenner 98698530Sfenner /* fill out the command */ 98798530Sfenner cm->cm_data = data; 98898530Sfenner cm->cm_datalen = dumppages * PAGE_SIZE; 98998530Sfenner cm->cm_complete = NULL; 99017683Spst cm->cm_private = NULL; 99117683Spst cm->cm_timestamp = time_second; 99298530Sfenner cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 99398530Sfenner 99417683Spst /* build the FIB */ 99517683Spst fib = cm->cm_fib; 99617683Spst fib->Header.XferState = 99717683Spst AAC_FIBSTATE_HOSTOWNED | 99817683Spst AAC_FIBSTATE_INITIALISED | 99917683Spst AAC_FIBSTATE_FROMHOST | 100017683Spst AAC_FIBSTATE_REXPECTED | 100117683Spst AAC_FIBSTATE_NORM; 100217683Spst fib->Header.Command = ContainerCommand; 100317683Spst fib->Header.Size = sizeof(struct aac_fib_header); 100417683Spst 100517683Spst bw = (struct aac_blockwrite *)&fib->data[0]; 100675107Sfenner bw->Command = VM_CtBlockWrite; 100775107Sfenner bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 100875107Sfenner bw->BlockNumber = lba; 100975107Sfenner bw->ByteCount = dumppages * PAGE_SIZE; 101075107Sfenner bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 101175107Sfenner fib->Header.Size += sizeof(struct aac_blockwrite); 101275107Sfenner cm->cm_flags |= AAC_CMD_DATAOUT; 101375107Sfenner cm->cm_sgtable = &bw->SgMap; 101475107Sfenner 101575107Sfenner return (aac_start(cm)); 101617683Spst} 101717683Spst 101875107Sfenner/* 101975107Sfenner * Wait for the card's queue to drain when dumping. Also check for monitor 102017683Spst * printf's 102117683Spst */ 102217683Spstvoid 102317683Spstaac_dump_complete(struct aac_softc *sc) 102417683Spst{ 102517683Spst struct aac_fib *fib; 102617683Spst struct aac_command *cm; 102717683Spst u_int16_t reason; 102817683Spst u_int32_t pi, ci, fib_size; 102956889Sfenner 103075107Sfenner do { 103175107Sfenner reason = AAC_GET_ISTATUS(sc); 103256889Sfenner if (reason & AAC_DB_RESPONSE_READY) { 103375107Sfenner AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 103475107Sfenner for (;;) { 103556889Sfenner if (aac_dequeue_fib(sc, 103656889Sfenner AAC_HOST_NORM_RESP_QUEUE, 103717683Spst &fib_size, &fib)) 103817683Spst break; 103917683Spst cm = (struct aac_command *) 104017683Spst fib->Header.SenderData; 104117683Spst if (cm == NULL) 104217683Spst AAC_PRINT_FIB(sc, fib); 104375107Sfenner else { 104475107Sfenner aac_remove_busy(cm); 104517683Spst aac_unmap_command(cm); 104617683Spst aac_enqueue_complete(cm); 104717683Spst aac_release_command(cm); 104817683Spst } 104917683Spst } 105017683Spst } 105117683Spst if (reason & AAC_DB_PRINTF) { 105217683Spst AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF); 105317683Spst aac_print_printf(sc); 105417683Spst } 105517683Spst pi = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][ 105617683Spst AAC_PRODUCER_INDEX]; 105717683Spst ci = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][ 105875107Sfenner AAC_CONSUMER_INDEX]; 105975107Sfenner } while (ci != pi); 106017683Spst 106117683Spst return; 106217683Spst} 106317683Spst 106417683Spst/* 106517683Spst * Submit a command to the controller, return when it completes. 1066 */ 1067static int 1068aac_wait_command(struct aac_command *cm, int timeout) 1069{ 1070 int s, error = 0; 1071 1072 debug_called(2); 1073 1074 /* Put the command on the ready queue and get things going */ 1075 cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 1076 aac_enqueue_ready(cm); 1077 aac_startio(cm->cm_sc); 1078 s = splbio(); 1079 while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1080 error = tsleep(cm, PRIBIO | PCATCH, "aacwait", 0); 1081 if ((error == ERESTART) || (error == EINTR)) 1082 break; 1083 } 1084 splx(s); 1085 return(error); 1086} 1087 1088/* 1089 *Command Buffer Management 1090 */ 1091 1092/* 1093 * Allocate a command. 1094 */ 1095static int 1096aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1097{ 1098 struct aac_command *cm; 1099 1100 debug_called(3); 1101 1102 if ((cm = aac_dequeue_free(sc)) == NULL) 1103 return(ENOMEM); 1104 1105 *cmp = cm; 1106 return(0); 1107} 1108 1109/* 1110 * Release a command back to the freelist. 1111 */ 1112static void 1113aac_release_command(struct aac_command *cm) 1114{ 1115 debug_called(3); 1116 1117 /* (re)initialise the command/FIB */ 1118 cm->cm_sgtable = NULL; 1119 cm->cm_flags = 0; 1120 cm->cm_complete = NULL; 1121 cm->cm_private = NULL; 1122 cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1123 cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1124 cm->cm_fib->Header.Flags = 0; 1125 cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 1126 1127 /* 1128 * These are duplicated in aac_start to cover the case where an 1129 * intermediate stage may have destroyed them. They're left 1130 * initialised here for debugging purposes only. 1131 */ 1132 cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1133 cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 1134 1135 aac_enqueue_free(cm); 1136} 1137 1138/* 1139 * Map helper for command/FIB allocation. 1140 */ 1141static void 1142aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1143{ 1144 struct aac_softc *sc; 1145 1146 sc = (struct aac_softc *)arg; 1147 1148 debug_called(3); 1149 1150 sc->aac_fibphys = segs[0].ds_addr; 1151} 1152 1153/* 1154 * Allocate and initialise commands/FIBs for this adapter. 1155 */ 1156static int 1157aac_alloc_commands(struct aac_softc *sc) 1158{ 1159 struct aac_command *cm; 1160 int i; 1161 1162 debug_called(1); 1163 1164 /* allocate the FIBs in DMAable memory and load them */ 1165 if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, 1166 BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 1167 return(ENOMEM); 1168 } 1169 bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 1170 AAC_FIB_COUNT * sizeof(struct aac_fib), 1171 aac_map_command_helper, sc, 0); 1172 1173 /* initialise constant fields in the command structure */ 1174 for (i = 0; i < AAC_FIB_COUNT; i++) { 1175 cm = &sc->aac_command[i]; 1176 cm->cm_sc = sc; 1177 cm->cm_fib = sc->aac_fibs + i; 1178 cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 1179 1180 if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 1181 aac_release_command(cm); 1182 } 1183 return(0); 1184} 1185 1186/* 1187 * Free FIBs owned by this adapter. 1188 */ 1189static void 1190aac_free_commands(struct aac_softc *sc) 1191{ 1192 int i; 1193 1194 debug_called(1); 1195 1196 for (i = 0; i < AAC_FIB_COUNT; i++) 1197 bus_dmamap_destroy(sc->aac_buffer_dmat, 1198 sc->aac_command[i].cm_datamap); 1199 1200 bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 1201 bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 1202} 1203 1204/* 1205 * Command-mapping helper function - populate this command's s/g table. 1206 */ 1207static void 1208aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1209{ 1210 struct aac_command *cm; 1211 struct aac_fib *fib; 1212 struct aac_sg_table *sg; 1213 int i; 1214 1215 debug_called(3); 1216 1217 cm = (struct aac_command *)arg; 1218 fib = cm->cm_fib; 1219 1220 /* find the s/g table */ 1221 sg = cm->cm_sgtable; 1222 1223 /* copy into the FIB */ 1224 if (sg != NULL) { 1225 sg->SgCount = nseg; 1226 for (i = 0; i < nseg; i++) { 1227 sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1228 sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1229 } 1230 /* update the FIB size for the s/g count */ 1231 fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1232 } 1233 1234} 1235 1236/* 1237 * Map a command into controller-visible space. 1238 */ 1239static void 1240aac_map_command(struct aac_command *cm) 1241{ 1242 struct aac_softc *sc; 1243 1244 debug_called(2); 1245 1246 sc = cm->cm_sc; 1247 1248 /* don't map more than once */ 1249 if (cm->cm_flags & AAC_CMD_MAPPED) 1250 return; 1251 1252 if (cm->cm_datalen != 0) { 1253 bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1254 cm->cm_data, cm->cm_datalen, 1255 aac_map_command_sg, cm, 0); 1256 1257 if (cm->cm_flags & AAC_CMD_DATAIN) 1258 bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1259 BUS_DMASYNC_PREREAD); 1260 if (cm->cm_flags & AAC_CMD_DATAOUT) 1261 bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1262 BUS_DMASYNC_PREWRITE); 1263 } 1264 cm->cm_flags |= AAC_CMD_MAPPED; 1265} 1266 1267/* 1268 * Unmap a command from controller-visible space. 1269 */ 1270static void 1271aac_unmap_command(struct aac_command *cm) 1272{ 1273 struct aac_softc *sc; 1274 1275 debug_called(2); 1276 1277 sc = cm->cm_sc; 1278 1279 if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1280 return; 1281 1282 if (cm->cm_datalen != 0) { 1283 if (cm->cm_flags & AAC_CMD_DATAIN) 1284 bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1285 BUS_DMASYNC_POSTREAD); 1286 if (cm->cm_flags & AAC_CMD_DATAOUT) 1287 bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1288 BUS_DMASYNC_POSTWRITE); 1289 1290 bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1291 } 1292 cm->cm_flags &= ~AAC_CMD_MAPPED; 1293} 1294 1295/* 1296 * Hardware Interface 1297 */ 1298 1299/* 1300 * Initialise the adapter. 1301 */ 1302static void 1303aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1304{ 1305 struct aac_softc *sc; 1306 1307 debug_called(1); 1308 1309 sc = (struct aac_softc *)arg; 1310 1311 sc->aac_common_busaddr = segs[0].ds_addr; 1312} 1313 1314static int 1315aac_init(struct aac_softc *sc) 1316{ 1317 struct aac_adapter_init *ip; 1318 time_t then; 1319 u_int32_t code; 1320 u_int8_t *qaddr; 1321 1322 debug_called(1); 1323 1324 /* 1325 * First wait for the adapter to come ready. 1326 */ 1327 then = time_second; 1328 do { 1329 code = AAC_GET_FWSTATUS(sc); 1330 if (code & AAC_SELF_TEST_FAILED) { 1331 device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1332 return(ENXIO); 1333 } 1334 if (code & AAC_KERNEL_PANIC) { 1335 device_printf(sc->aac_dev, 1336 "FATAL: controller kernel panic\n"); 1337 return(ENXIO); 1338 } 1339 if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1340 device_printf(sc->aac_dev, 1341 "FATAL: controller not coming ready, " 1342 "status %x\n", code); 1343 return(ENXIO); 1344 } 1345 } while (!(code & AAC_UP_AND_RUNNING)); 1346 1347 /* 1348 * Create DMA tag for the common structure and allocate it. 1349 */ 1350 if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1351 1, 0, /* algnmnt, boundary */ 1352 BUS_SPACE_MAXADDR, /* lowaddr */ 1353 BUS_SPACE_MAXADDR, /* highaddr */ 1354 NULL, NULL, /* filter, filterarg */ 1355 sizeof(struct aac_common), /* maxsize */ 1356 1, /* nsegments */ 1357 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1358 0, /* flags */ 1359 &sc->aac_common_dmat)) { 1360 device_printf(sc->aac_dev, 1361 "can't allocate common structure DMA tag\n"); 1362 return(ENOMEM); 1363 } 1364 if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1365 BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 1366 device_printf(sc->aac_dev, "can't allocate common structure\n"); 1367 return(ENOMEM); 1368 } 1369 bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1370 sc->aac_common, sizeof(*sc->aac_common), aac_common_map, 1371 sc, 0); 1372 bzero(sc->aac_common, sizeof(*sc->aac_common)); 1373 1374 /* 1375 * Fill in the init structure. This tells the adapter about the 1376 * physical location of various important shared data structures. 1377 */ 1378 ip = &sc->aac_common->ac_init; 1379 ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1380 1381 ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1382 offsetof(struct aac_common, ac_fibs); 1383 ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0]; 1384 ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1385 ip->AdapterFibAlign = sizeof(struct aac_fib); 1386 1387 ip->PrintfBufferAddress = sc->aac_common_busaddr + 1388 offsetof(struct aac_common, ac_printf); 1389 ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1390 1391 ip->HostPhysMemPages = 0; /* not used? */ 1392 ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 1393 1394 /* 1395 * Initialise FIB queues. Note that it appears that the layout of the 1396 * indexes and the segmentation of the entries may be mandated by the 1397 * adapter, which is only told about the base of the queue index fields. 1398 * 1399 * The initial values of the indices are assumed to inform the adapter 1400 * of the sizes of the respective queues, and theoretically it could 1401 * work out the entire layout of the queue structures from this. We 1402 * take the easy route and just lay this area out like everyone else 1403 * does. 1404 * 1405 * The Linux driver uses a much more complex scheme whereby several 1406 * header records are kept for each queue. We use a couple of generic 1407 * list manipulation functions which 'know' the size of each list by 1408 * virtue of a table. 1409 */ 1410 qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 1411 qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 1412 sc->aac_queues = (struct aac_queue_table *)qaddr; 1413 ip->CommHeaderAddress = sc->aac_common_busaddr + 1414 ((u_int32_t)sc->aac_queues - 1415 (u_int32_t)sc->aac_common); 1416 bzero(sc->aac_queues, sizeof(struct aac_queue_table)); 1417 1418 sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1419 AAC_HOST_NORM_CMD_ENTRIES; 1420 sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1421 AAC_HOST_NORM_CMD_ENTRIES; 1422 sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1423 AAC_HOST_HIGH_CMD_ENTRIES; 1424 sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1425 AAC_HOST_HIGH_CMD_ENTRIES; 1426 sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1427 AAC_ADAP_NORM_CMD_ENTRIES; 1428 sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1429 AAC_ADAP_NORM_CMD_ENTRIES; 1430 sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1431 AAC_ADAP_HIGH_CMD_ENTRIES; 1432 sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1433 AAC_ADAP_HIGH_CMD_ENTRIES; 1434 sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1435 AAC_HOST_NORM_RESP_ENTRIES; 1436 sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1437 AAC_HOST_NORM_RESP_ENTRIES; 1438 sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1439 AAC_HOST_HIGH_RESP_ENTRIES; 1440 sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1441 AAC_HOST_HIGH_RESP_ENTRIES; 1442 sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1443 AAC_ADAP_NORM_RESP_ENTRIES; 1444 sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1445 AAC_ADAP_NORM_RESP_ENTRIES; 1446 sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1447 AAC_ADAP_HIGH_RESP_ENTRIES; 1448 sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1449 AAC_ADAP_HIGH_RESP_ENTRIES; 1450 sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1451 &sc->aac_queues->qt_HostNormCmdQueue[0]; 1452 sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1453 &sc->aac_queues->qt_HostHighCmdQueue[0]; 1454 sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1455 &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1456 sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1457 &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1458 sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1459 &sc->aac_queues->qt_HostNormRespQueue[0]; 1460 sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1461 &sc->aac_queues->qt_HostHighRespQueue[0]; 1462 sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1463 &sc->aac_queues->qt_AdapNormRespQueue[0]; 1464 sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1465 &sc->aac_queues->qt_AdapHighRespQueue[0]; 1466 1467 /* 1468 * Do controller-type-specific initialisation 1469 */ 1470 switch (sc->aac_hwif) { 1471 case AAC_HWIF_I960RX: 1472 AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 1473 break; 1474 } 1475 1476 /* 1477 * Give the init structure to the controller. 1478 */ 1479 if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1480 sc->aac_common_busaddr + 1481 offsetof(struct aac_common, ac_init), 0, 0, 0, 1482 NULL)) { 1483 device_printf(sc->aac_dev, 1484 "error establishing init structure\n"); 1485 return(EIO); 1486 } 1487 1488 return(0); 1489} 1490 1491/* 1492 * Send a synchronous command to the controller and wait for a result. 1493 */ 1494static int 1495aac_sync_command(struct aac_softc *sc, u_int32_t command, 1496 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 1497 u_int32_t *sp) 1498{ 1499 time_t then; 1500 u_int32_t status; 1501 1502 debug_called(3); 1503 1504 /* populate the mailbox */ 1505 AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 1506 1507 /* ensure the sync command doorbell flag is cleared */ 1508 AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1509 1510 /* then set it to signal the adapter */ 1511 AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 1512 1513 /* spin waiting for the command to complete */ 1514 then = time_second; 1515 do { 1516 if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1517 debug(2, "timed out"); 1518 return(EIO); 1519 } 1520 } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 1521 1522 /* clear the completion flag */ 1523 AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1524 1525 /* get the command status */ 1526 status = AAC_GET_MAILBOXSTATUS(sc); 1527 if (sp != NULL) 1528 *sp = status; 1529 return(0); 1530} 1531 1532/* 1533 * Send a synchronous FIB to the controller and wait for a result. 1534 */ 1535static int 1536aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1537 void *data, u_int16_t datasize, 1538 void *result, u_int16_t *resultsize) 1539{ 1540 struct aac_fib *fib; 1541 1542 debug_called(3); 1543 1544 fib = &sc->aac_common->ac_sync_fib; 1545 1546 if (datasize > AAC_FIB_DATASIZE) 1547 return(EINVAL); 1548 1549 /* 1550 * Set up the sync FIB 1551 */ 1552 fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1553 AAC_FIBSTATE_INITIALISED | 1554 AAC_FIBSTATE_EMPTY; 1555 fib->Header.XferState |= xferstate; 1556 fib->Header.Command = command; 1557 fib->Header.StructType = AAC_FIBTYPE_TFIB; 1558 fib->Header.Size = sizeof(struct aac_fib) + datasize; 1559 fib->Header.SenderSize = sizeof(struct aac_fib); 1560 fib->Header.SenderFibAddress = (u_int32_t)fib; 1561 fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1562 offsetof(struct aac_common, 1563 ac_sync_fib); 1564 1565 /* 1566 * Copy in data. 1567 */ 1568 if (data != NULL) { 1569 KASSERT(datasize <= sizeof(fib->data), 1570 ("aac_sync_fib: datasize to large")); 1571 bcopy(data, fib->data, datasize); 1572 fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | 1573 AAC_FIBSTATE_NORM; 1574 } 1575 1576 /* 1577 * Give the FIB to the controller, wait for a response. 1578 */ 1579 if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1580 fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 1581 debug(2, "IO error"); 1582 return(EIO); 1583 } 1584 1585 /* 1586 * Copy out the result 1587 */ 1588 if (result != NULL) { 1589 u_int copysize; 1590 1591 copysize = fib->Header.Size - sizeof(struct aac_fib_header); 1592 if (copysize > *resultsize) 1593 copysize = *resultsize; 1594 *resultsize = fib->Header.Size - sizeof(struct aac_fib_header); 1595 bcopy(fib->data, result, copysize); 1596 } 1597 return(0); 1598} 1599 1600/* 1601 * Adapter-space FIB queue manipulation 1602 * 1603 * Note that the queue implementation here is a little funky; neither the PI or 1604 * CI will ever be zero. This behaviour is a controller feature. 1605 */ 1606static struct { 1607 int size; 1608 int notify; 1609} aac_qinfo[] = { 1610 {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 1611 {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 1612 {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 1613 {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 1614 {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 1615 {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 1616 {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 1617 {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 1618}; 1619 1620/* 1621 * Atomically insert an entry into the nominated queue, returns 0 on success or 1622 * EBUSY if the queue is full. 1623 * 1624 * Note: it would be more efficient to defer notifying the controller in 1625 * the case where we may be inserting several entries in rapid succession, 1626 * but implementing this usefully may be difficult (it would involve a 1627 * separate queue/notify interface). 1628 */ 1629static int 1630aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 1631{ 1632 u_int32_t pi, ci; 1633 int s, error; 1634 u_int32_t fib_size; 1635 u_int32_t fib_addr; 1636 1637 debug_called(3); 1638 1639 fib_size = cm->cm_fib->Header.Size; 1640 fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 1641 1642 s = splbio(); 1643 1644 /* get the producer/consumer indices */ 1645 pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1646 ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1647 1648 /* wrap the queue? */ 1649 if (pi >= aac_qinfo[queue].size) 1650 pi = 0; 1651 1652 /* check for queue full */ 1653 if ((pi + 1) == ci) { 1654 error = EBUSY; 1655 goto out; 1656 } 1657 1658 /* populate queue entry */ 1659 (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 1660 (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 1661 1662 /* update producer index */ 1663 sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 1664 1665 /* 1666 * To avoid a race with its completion interrupt, place this command on 1667 * the busy queue prior to advertising it to the controller. 1668 */ 1669 aac_enqueue_busy(cm); 1670 1671 /* notify the adapter if we know how */ 1672 if (aac_qinfo[queue].notify != 0) 1673 AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1674 1675 error = 0; 1676 1677out: 1678 splx(s); 1679 return(error); 1680} 1681 1682/* 1683 * Atomically remove one entry from the nominated queue, returns 0 on 1684 * success or ENOENT if the queue is empty. 1685 */ 1686static int 1687aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1688 struct aac_fib **fib_addr) 1689{ 1690 u_int32_t pi, ci; 1691 int s, error; 1692 int notify; 1693 1694 debug_called(3); 1695 1696 s = splbio(); 1697 1698 /* get the producer/consumer indices */ 1699 pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1700 ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1701 1702 /* check for queue empty */ 1703 if (ci == pi) { 1704 error = ENOENT; 1705 goto out; 1706 } 1707 1708 notify = 0; 1709 if (ci == pi + 1) 1710 notify++; 1711 1712 /* wrap the queue? */ 1713 if (ci >= aac_qinfo[queue].size) 1714 ci = 0; 1715 1716 /* fetch the entry */ 1717 *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1718 *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1719 ci)->aq_fib_addr; 1720 1721 /* update consumer index */ 1722 sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 1723 1724 /* if we have made the queue un-full, notify the adapter */ 1725 if (notify && (aac_qinfo[queue].notify != 0)) 1726 AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1727 error = 0; 1728 1729out: 1730 splx(s); 1731 return(error); 1732} 1733 1734/* 1735 * Put our response to an Adapter Initialed Fib on the response queue 1736 */ 1737static int 1738aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 1739{ 1740 u_int32_t pi, ci; 1741 int s, error; 1742 u_int32_t fib_size; 1743 u_int32_t fib_addr; 1744 1745 debug_called(1); 1746 1747 /* Tell the adapter where the FIB is */ 1748 fib_size = fib->Header.Size; 1749 fib_addr = fib->Header.SenderFibAddress; 1750 fib->Header.ReceiverFibAddress = fib_addr; 1751 1752 s = splbio(); 1753 1754 /* get the producer/consumer indices */ 1755 pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1756 ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1757 1758 /* wrap the queue? */ 1759 if (pi >= aac_qinfo[queue].size) 1760 pi = 0; 1761 1762 /* check for queue full */ 1763 if ((pi + 1) == ci) { 1764 error = EBUSY; 1765 goto out; 1766 } 1767 1768 /* populate queue entry */ 1769 (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 1770 (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 1771 1772 /* update producer index */ 1773 sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 1774 1775 /* notify the adapter if we know how */ 1776 if (aac_qinfo[queue].notify != 0) 1777 AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1778 1779 error = 0; 1780 1781out: 1782 splx(s); 1783 return(error); 1784} 1785 1786/* 1787 * Check for commands that have been outstanding for a suspiciously long time, 1788 * and complain about them. 1789 */ 1790static void 1791aac_timeout(struct aac_softc *sc) 1792{ 1793 int s; 1794 struct aac_command *cm; 1795 time_t deadline; 1796 1797#if 0 1798 /* simulate an interrupt to handle possibly-missed interrupts */ 1799 /* 1800 * XXX This was done to work around another bug which has since been 1801 * fixed. It is dangerous anyways because you don't want multiple 1802 * threads in the interrupt handler at the same time! If calling 1803 * is deamed neccesary in the future, proper mutexes must be used. 1804 */ 1805 s = splbio(); 1806 aac_intr(sc); 1807 splx(s); 1808 1809 /* kick the I/O queue to restart it in the case of deadlock */ 1810 aac_startio(sc); 1811#endif 1812 1813 /* 1814 * traverse the busy command list, bitch about late commands once 1815 * only. 1816 */ 1817 deadline = time_second - AAC_CMD_TIMEOUT; 1818 s = splbio(); 1819 TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1820 if ((cm->cm_timestamp < deadline) 1821 /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 1822 cm->cm_flags |= AAC_CMD_TIMEDOUT; 1823 device_printf(sc->aac_dev, 1824 "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1825 cm, (int)(time_second-cm->cm_timestamp)); 1826 AAC_PRINT_FIB(sc, cm->cm_fib); 1827 } 1828 } 1829 splx(s); 1830 1831 /* reset the timer for next time */ 1832 timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 1833 return; 1834} 1835 1836/* 1837 * Interface Function Vectors 1838 */ 1839 1840/* 1841 * Read the current firmware status word. 1842 */ 1843static int 1844aac_sa_get_fwstatus(struct aac_softc *sc) 1845{ 1846 debug_called(3); 1847 1848 return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 1849} 1850 1851static int 1852aac_rx_get_fwstatus(struct aac_softc *sc) 1853{ 1854 debug_called(3); 1855 1856 return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 1857} 1858 1859/* 1860 * Notify the controller of a change in a given queue 1861 */ 1862 1863static void 1864aac_sa_qnotify(struct aac_softc *sc, int qbit) 1865{ 1866 debug_called(3); 1867 1868 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 1869} 1870 1871static void 1872aac_rx_qnotify(struct aac_softc *sc, int qbit) 1873{ 1874 debug_called(3); 1875 1876 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 1877} 1878 1879/* 1880 * Get the interrupt reason bits 1881 */ 1882static int 1883aac_sa_get_istatus(struct aac_softc *sc) 1884{ 1885 debug_called(3); 1886 1887 return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 1888} 1889 1890static int 1891aac_rx_get_istatus(struct aac_softc *sc) 1892{ 1893 debug_called(3); 1894 1895 return(AAC_GETREG4(sc, AAC_RX_ODBR)); 1896} 1897 1898/* 1899 * Clear some interrupt reason bits 1900 */ 1901static void 1902aac_sa_clear_istatus(struct aac_softc *sc, int mask) 1903{ 1904 debug_called(3); 1905 1906 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 1907} 1908 1909static void 1910aac_rx_clear_istatus(struct aac_softc *sc, int mask) 1911{ 1912 debug_called(3); 1913 1914 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 1915} 1916 1917/* 1918 * Populate the mailbox and set the command word 1919 */ 1920static void 1921aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 1922 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1923{ 1924 debug_called(4); 1925 1926 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 1927 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 1928 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 1929 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 1930 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 1931} 1932 1933static void 1934aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 1935 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1936{ 1937 debug_called(4); 1938 1939 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 1940 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 1941 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 1942 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 1943 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 1944} 1945 1946/* 1947 * Fetch the immediate command status word 1948 */ 1949static int 1950aac_sa_get_mailboxstatus(struct aac_softc *sc) 1951{ 1952 debug_called(4); 1953 1954 return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 1955} 1956 1957static int 1958aac_rx_get_mailboxstatus(struct aac_softc *sc) 1959{ 1960 debug_called(4); 1961 1962 return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 1963} 1964 1965/* 1966 * Set/clear interrupt masks 1967 */ 1968static void 1969aac_sa_set_interrupts(struct aac_softc *sc, int enable) 1970{ 1971 debug(2, "%sable interrupts", enable ? "en" : "dis"); 1972 1973 if (enable) { 1974 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 1975 } else { 1976 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 1977 } 1978} 1979 1980static void 1981aac_rx_set_interrupts(struct aac_softc *sc, int enable) 1982{ 1983 debug(2, "%sable interrupts", enable ? "en" : "dis"); 1984 1985 if (enable) { 1986 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 1987 } else { 1988 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 1989 } 1990} 1991 1992/* 1993 * Debugging and Diagnostics 1994 */ 1995 1996/* 1997 * Print some information about the controller. 1998 */ 1999static void 2000aac_describe_controller(struct aac_softc *sc) 2001{ 2002 u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX really a bit big 2003 * for the stack */ 2004 u_int16_t bufsize; 2005 struct aac_adapter_info *info; 2006 u_int8_t arg; 2007 2008 debug_called(2); 2009 2010 arg = 0; 2011 bufsize = sizeof(buf); 2012 if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf, 2013 &bufsize)) { 2014 device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2015 return; 2016 } 2017 if (bufsize != sizeof(*info)) { 2018 device_printf(sc->aac_dev, 2019 "RequestAdapterInfo returned wrong data size " 2020 "(%d != %d)\n", bufsize, sizeof(*info)); 2021 /*return;*/ 2022 } 2023 info = (struct aac_adapter_info *)&buf[0]; 2024 2025 device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2026 aac_describe_code(aac_cpu_variant, info->CpuVariant), 2027 info->ClockSpeed, info->BufferMem / (1024 * 1024), 2028 aac_describe_code(aac_battery_platform, 2029 info->batteryPlatform)); 2030 2031 /* save the kernel revision structure for later use */ 2032 sc->aac_revision = info->KernelRevision; 2033 device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2034 info->KernelRevision.external.comp.major, 2035 info->KernelRevision.external.comp.minor, 2036 info->KernelRevision.external.comp.dash, 2037 info->KernelRevision.buildNumber, 2038 (u_int32_t)(info->SerialNumber & 0xffffff)); 2039} 2040 2041/* 2042 * Look up a text description of a numeric error code and return a pointer to 2043 * same. 2044 */ 2045static char * 2046aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2047{ 2048 int i; 2049 2050 for (i = 0; table[i].string != NULL; i++) 2051 if (table[i].code == code) 2052 return(table[i].string); 2053 return(table[i + 1].string); 2054} 2055 2056/* 2057 * Management Interface 2058 */ 2059 2060static int 2061aac_open(dev_t dev, int flags, int fmt, struct proc *p) 2062{ 2063 struct aac_softc *sc; 2064 2065 debug_called(2); 2066 2067 sc = dev->si_drv1; 2068 2069 /* Check to make sure the device isn't already open */ 2070 if (sc->aac_state & AAC_STATE_OPEN) { 2071 return EBUSY; 2072 } 2073 sc->aac_state |= AAC_STATE_OPEN; 2074 2075 return 0; 2076} 2077 2078static int 2079aac_close(dev_t dev, int flags, int fmt, struct proc *p) 2080{ 2081 struct aac_softc *sc; 2082 2083 debug_called(2); 2084 2085 sc = dev->si_drv1; 2086 2087 /* Mark this unit as no longer open */ 2088 sc->aac_state &= ~AAC_STATE_OPEN; 2089 2090 return 0; 2091} 2092 2093static int 2094aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 2095{ 2096 union aac_statrequest *as; 2097 struct aac_softc *sc; 2098 int error = 0; 2099 int i; 2100 2101 debug_called(2); 2102 2103 as = (union aac_statrequest *)arg; 2104 sc = dev->si_drv1; 2105 2106 switch (cmd) { 2107 case AACIO_STATS: 2108 switch (as->as_item) { 2109 case AACQ_FREE: 2110 case AACQ_BIO: 2111 case AACQ_READY: 2112 case AACQ_BUSY: 2113 case AACQ_COMPLETE: 2114 bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2115 sizeof(struct aac_qstat)); 2116 break; 2117 default: 2118 error = ENOENT; 2119 break; 2120 } 2121 break; 2122 2123 case FSACTL_SENDFIB: 2124 arg = *(caddr_t*)arg; 2125 case FSACTL_LNX_SENDFIB: 2126 debug(1, "FSACTL_SENDFIB"); 2127 error = aac_ioctl_sendfib(sc, arg); 2128 break; 2129 case FSACTL_AIF_THREAD: 2130 case FSACTL_LNX_AIF_THREAD: 2131 debug(1, "FSACTL_AIF_THREAD"); 2132 error = EINVAL; 2133 break; 2134 case FSACTL_OPEN_GET_ADAPTER_FIB: 2135 arg = *(caddr_t*)arg; 2136 case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2137 debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2138 /* 2139 * Pass the caller out an AdapterFibContext. 2140 * 2141 * Note that because we only support one opener, we 2142 * basically ignore this. Set the caller's context to a magic 2143 * number just in case. 2144 * 2145 * The Linux code hands the driver a pointer into kernel space, 2146 * and then trusts it when the caller hands it back. Aiee! 2147 * Here, we give it the proc pointer of the per-adapter aif 2148 * thread. It's only used as a sanity check in other calls. 2149 */ 2150 i = (int)sc->aifthread; 2151 error = copyout(&i, arg, sizeof(i)); 2152 break; 2153 case FSACTL_GET_NEXT_ADAPTER_FIB: 2154 arg = *(caddr_t*)arg; 2155 case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2156 debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2157 error = aac_getnext_aif(sc, arg); 2158 break; 2159 case FSACTL_CLOSE_GET_ADAPTER_FIB: 2160 case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2161 debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2162 /* don't do anything here */ 2163 break; 2164 case FSACTL_MINIPORT_REV_CHECK: 2165 arg = *(caddr_t*)arg; 2166 case FSACTL_LNX_MINIPORT_REV_CHECK: 2167 debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2168 error = aac_rev_check(sc, arg); 2169 break; 2170 case FSACTL_QUERY_DISK: 2171 arg = *(caddr_t*)arg; 2172 case FSACTL_LNX_QUERY_DISK: 2173 debug(1, "FSACTL_QUERY_DISK"); 2174 error = aac_query_disk(sc, arg); 2175 break; 2176 case FSACTL_DELETE_DISK: 2177 case FSACTL_LNX_DELETE_DISK: 2178 /* 2179 * We don't trust the underland to tell us when to delete a 2180 * container, rather we rely on an AIF coming from the 2181 * controller 2182 */ 2183 error = 0; 2184 break; 2185 default: 2186 device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd); 2187 error = EINVAL; 2188 break; 2189 } 2190 return(error); 2191} 2192 2193/* 2194 * Send a FIB supplied from userspace 2195 */ 2196static int 2197aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2198{ 2199 struct aac_command *cm; 2200 int size, error; 2201 2202 debug_called(2); 2203 2204 cm = NULL; 2205 2206 /* 2207 * Get a command 2208 */ 2209 if (aac_alloc_command(sc, &cm)) { 2210 error = EBUSY; 2211 goto out; 2212 } 2213 2214 /* 2215 * Fetch the FIB header, then re-copy to get data as well. 2216 */ 2217 if ((error = copyin(ufib, cm->cm_fib, 2218 sizeof(struct aac_fib_header))) != 0) 2219 goto out; 2220 size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2221 if (size > sizeof(struct aac_fib)) { 2222 device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2223 size, sizeof(struct aac_fib)); 2224 size = sizeof(struct aac_fib); 2225 } 2226 if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2227 goto out; 2228 cm->cm_fib->Header.Size = size; 2229 cm->cm_timestamp = time_second; 2230 2231 /* 2232 * Pass the FIB to the controller, wait for it to complete. 2233 */ 2234 if ((error = aac_wait_command(cm, 30)) != 0) /* XXX user timeout? */ 2235 goto out; 2236 2237 /* 2238 * Copy the FIB and data back out to the caller. 2239 */ 2240 size = cm->cm_fib->Header.Size; 2241 if (size > sizeof(struct aac_fib)) { 2242 device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2243 size, sizeof(struct aac_fib)); 2244 size = sizeof(struct aac_fib); 2245 } 2246 error = copyout(cm->cm_fib, ufib, size); 2247 2248out: 2249 if (cm != NULL) { 2250 aac_release_command(cm); 2251 } 2252 return(error); 2253} 2254 2255/* 2256 * Handle an AIF sent to us by the controller; queue it for later reference. 2257 * If the queue fills up, then drop the older entries. 2258 */ 2259static void 2260aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 2261{ 2262 struct aac_aif_command *aif; 2263 struct aac_container *co, *co_next; 2264 struct aac_mntinfo mi; 2265 struct aac_mntinforesponse mir; 2266 u_int16_t rsize; 2267 int next, s, found; 2268 int added = 0, i = 0; 2269 2270 debug_called(2); 2271 2272 aif = (struct aac_aif_command*)&fib->data[0]; 2273 aac_print_aif(sc, aif); 2274 2275 /* Is it an event that we should care about? */ 2276 switch (aif->command) { 2277 case AifCmdEventNotify: 2278 switch (aif->data.EN.type) { 2279 case AifEnAddContainer: 2280 case AifEnDeleteContainer: 2281 /* 2282 * A container was added or deleted, but the message 2283 * doesn't tell us anything else! Re-enumerate the 2284 * containers and sort things out. 2285 */ 2286 mi.Command = VM_NameServe; 2287 mi.MntType = FT_FILESYS; 2288 do { 2289 /* 2290 * Ask the controller for its containers one at 2291 * a time. 2292 * XXX What if the controller's list changes 2293 * midway through this enumaration? 2294 * XXX This should be done async. 2295 */ 2296 mi.MntCount = i; 2297 rsize = sizeof(mir); 2298 if (aac_sync_fib(sc, ContainerCommand, 0, &mi, 2299 sizeof(mi), &mir, &rsize)) { 2300 debug(2, "Error probing container %d\n", 2301 i); 2302 continue; 2303 } 2304 if (rsize != sizeof(mir)) { 2305 debug(2, "Container response size too " 2306 "large\n"); 2307 continue; 2308 } 2309 /* 2310 * Check the container against our list. 2311 * co->co_found was already set to 0 in a 2312 * previous run. 2313 */ 2314 if ((mir.Status == ST_OK) && 2315 (mir.MntTable[0].VolType != CT_NONE)) { 2316 found = 0; 2317 TAILQ_FOREACH(co, 2318 &sc->aac_container_tqh, 2319 co_link) { 2320 if (co->co_mntobj.ObjectId == 2321 mir.MntTable[0].ObjectId) { 2322 co->co_found = 1; 2323 found = 1; 2324 break; 2325 } 2326 } 2327 /* 2328 * If the container matched, continue 2329 * in the list. 2330 */ 2331 if (found) { 2332 i++; 2333 continue; 2334 } 2335 2336 /* 2337 * This is a new container. Do all the 2338 * appropriate things to set it up. */ 2339 aac_add_container(sc, &mir, 1); 2340 added = 1; 2341 } 2342 i++; 2343 } while ((i < mir.MntRespCount) && 2344 (i < AAC_MAX_CONTAINERS)); 2345 2346 /* 2347 * Go through our list of containers and see which ones 2348 * were not marked 'found'. Since the controller didn't 2349 * list them they must have been deleted. Do the 2350 * appropriate steps to destroy the device. Also reset 2351 * the co->co_found field. 2352 */ 2353 co = TAILQ_FIRST(&sc->aac_container_tqh); 2354 while (co != NULL) { 2355 if (co->co_found == 0) { 2356 device_delete_child(sc->aac_dev, 2357 co->co_disk); 2358 co_next = TAILQ_NEXT(co, co_link); 2359 AAC_LOCK_AQUIRE(&sc-> 2360 aac_container_lock); 2361 TAILQ_REMOVE(&sc->aac_container_tqh, co, 2362 co_link); 2363 AAC_LOCK_RELEASE(&sc-> 2364 aac_container_lock); 2365 FREE(co, M_AACBUF); 2366 co = co_next; 2367 } else { 2368 co->co_found = 0; 2369 co = TAILQ_NEXT(co, co_link); 2370 } 2371 } 2372 2373 /* Attach the newly created containers */ 2374 if (added) 2375 bus_generic_attach(sc->aac_dev); 2376 2377 break; 2378 2379 default: 2380 break; 2381 } 2382 2383 default: 2384 break; 2385 } 2386 2387 /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2388 s = splbio(); 2389 next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 2390 if (next != sc->aac_aifq_tail) { 2391 bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 2392 sc->aac_aifq_head = next; 2393 if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 2394 wakeup(sc->aac_aifq); 2395 } 2396 splx(s); 2397 2398 return; 2399} 2400 2401/* 2402 * Linux Management Interface 2403 * This is soon to be removed! 2404 */ 2405 2406#ifdef AAC_COMPAT_LINUX 2407 2408#include <sys/proc.h> 2409#include <machine/../linux/linux.h> 2410#include <machine/../linux/linux_proto.h> 2411#include <compat/linux/linux_ioctl.h> 2412 2413/* There are multiple ioctl number ranges that need to be handled */ 2414#define AAC_LINUX_IOCTL_MIN 0x0000 2415#define AAC_LINUX_IOCTL_MAX 0x21ff 2416 2417static linux_ioctl_function_t aac_linux_ioctl; 2418static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl, 2419 AAC_LINUX_IOCTL_MIN, 2420 AAC_LINUX_IOCTL_MAX}; 2421 2422SYSINIT (aac_register, SI_SUB_KLD, SI_ORDER_MIDDLE, 2423 linux_ioctl_register_handler, &aac_handler); 2424SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, 2425 linux_ioctl_unregister_handler, &aac_handler); 2426 2427MODULE_DEPEND(aac, linux, 1, 1, 1); 2428 2429static int 2430aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args) 2431{ 2432 struct file *fp; 2433 u_long cmd; 2434 2435 debug_called(2); 2436 2437 fp = p->p_fd->fd_ofiles[args->fd]; 2438 cmd = args->cmd; 2439 2440 /* 2441 * Pass the ioctl off to our standard handler. 2442 */ 2443 return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p)); 2444} 2445 2446#endif 2447 2448/* 2449 * Return the Revision of the driver to userspace and check to see if the 2450 * userspace app is possibly compatible. This is extremely bogus since 2451 * our driver doesn't follow Adaptec's versioning system. Cheat by just 2452 * returning what the card reported. 2453 */ 2454static int 2455aac_rev_check(struct aac_softc *sc, caddr_t udata) 2456{ 2457 struct aac_rev_check rev_check; 2458 struct aac_rev_check_resp rev_check_resp; 2459 int error = 0; 2460 2461 debug_called(2); 2462 2463 /* 2464 * Copyin the revision struct from userspace 2465 */ 2466 if ((error = copyin(udata, (caddr_t)&rev_check, 2467 sizeof(struct aac_rev_check))) != 0) { 2468 return error; 2469 } 2470 2471 debug(2, "Userland revision= %d\n", 2472 rev_check.callingRevision.buildNumber); 2473 2474 /* 2475 * Doctor up the response struct. 2476 */ 2477 rev_check_resp.possiblyCompatible = 1; 2478 rev_check_resp.adapterSWRevision.external.ul = 2479 sc->aac_revision.external.ul; 2480 rev_check_resp.adapterSWRevision.buildNumber = 2481 sc->aac_revision.buildNumber; 2482 2483 return(copyout((caddr_t)&rev_check_resp, udata, 2484 sizeof(struct aac_rev_check_resp))); 2485} 2486 2487/* 2488 * Pass the caller the next AIF in their queue 2489 */ 2490static int 2491aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 2492{ 2493 struct get_adapter_fib_ioctl agf; 2494 int error, s; 2495 2496 debug_called(2); 2497 2498 if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 2499 2500 /* 2501 * Check the magic number that we gave the caller. 2502 */ 2503 if (agf.AdapterFibContext != (int)sc->aifthread) { 2504 error = EFAULT; 2505 } else { 2506 2507 s = splbio(); 2508 error = aac_return_aif(sc, agf.AifFib); 2509 2510 if ((error == EAGAIN) && (agf.Wait)) { 2511 sc->aac_state |= AAC_STATE_AIF_SLEEPER; 2512 while (error == EAGAIN) { 2513 error = tsleep(sc->aac_aifq, PRIBIO | 2514 PCATCH, "aacaif", 0); 2515 if (error == 0) 2516 error = aac_return_aif(sc, 2517 agf.AifFib); 2518 } 2519 sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 2520 } 2521 splx(s); 2522 } 2523 } 2524 return(error); 2525} 2526 2527/* 2528 * Hand the next AIF off the top of the queue out to userspace. 2529 */ 2530static int 2531aac_return_aif(struct aac_softc *sc, caddr_t uptr) 2532{ 2533 int error, s; 2534 2535 debug_called(2); 2536 2537 s = splbio(); 2538 if (sc->aac_aifq_tail == sc->aac_aifq_head) { 2539 error = EAGAIN; 2540 } else { 2541 error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2542 sizeof(struct aac_aif_command)); 2543 if (error) 2544 printf("aac_return_aif: copyout returned %d\n", error); 2545 if (!error) 2546 sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2547 AAC_AIFQ_LENGTH; 2548 } 2549 splx(s); 2550 return(error); 2551} 2552 2553/* 2554 * Give the userland some information about the container. The AAC arch 2555 * expects the driver to be a SCSI passthrough type driver, so it expects 2556 * the containers to have b:t:l numbers. Fake it. 2557 */ 2558static int 2559aac_query_disk(struct aac_softc *sc, caddr_t uptr) 2560{ 2561 struct aac_query_disk query_disk; 2562 struct aac_container *co; 2563 struct aac_disk *disk; 2564 int error, id; 2565 2566 debug_called(2); 2567 2568 disk = NULL; 2569 2570 error = copyin(uptr, (caddr_t)&query_disk, 2571 sizeof(struct aac_query_disk)); 2572 if (error) 2573 return (error); 2574 2575 id = query_disk.ContainerNumber; 2576 if (id == -1) 2577 return (EINVAL); 2578 2579 AAC_LOCK_AQUIRE(&sc->aac_container_lock); 2580 TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 2581 if (co->co_mntobj.ObjectId == id) 2582 break; 2583 } 2584 2585 if (co == NULL) { 2586 query_disk.Valid = 0; 2587 query_disk.Locked = 0; 2588 query_disk.Deleted = 1; /* XXX is this right? */ 2589 } else { 2590 disk = device_get_softc(co->co_disk); 2591 query_disk.Valid = 1; 2592 query_disk.Locked = 2593 (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 2594 query_disk.Deleted = 0; 2595 query_disk.Bus = 0; 2596 query_disk.Target = disk->unit; 2597 query_disk.Lun = 0; 2598 query_disk.UnMapped = 0; 2599 bcopy(disk->ad_dev_t->si_name, 2600 &query_disk.diskDeviceName[0], 10); 2601 } 2602 AAC_LOCK_RELEASE(&sc->aac_container_lock); 2603 2604 error = copyout((caddr_t)&query_disk, uptr, 2605 sizeof(struct aac_query_disk)); 2606 2607 return (error); 2608} 2609 2610