From owner-svn-src-all@FreeBSD.ORG Fri May 24 09:22:44 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id DA03F19B; Fri, 24 May 2013 09:22:44 +0000 (UTC) (envelope-from achim@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id C9244D52; Fri, 24 May 2013 09:22:44 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r4O9MiNi041203; Fri, 24 May 2013 09:22:44 GMT (envelope-from achim@svn.freebsd.org) Received: (from achim@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r4O9MhQL041192; Fri, 24 May 2013 09:22:43 GMT (envelope-from achim@svn.freebsd.org) Message-Id: <201305240922.r4O9MhQL041192@svn.freebsd.org> From: Achim Leubner Date: Fri, 24 May 2013 09:22:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r250963 - in head: share/man/man4 sys/amd64/conf sys/conf sys/dev/aacraid sys/i386/conf sys/ia64/conf sys/modules sys/modules/aacraid sys/modules/aacraid/aacraid_linux X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 24 May 2013 09:22:44 -0000 Author: achim Date: Fri May 24 09:22:43 2013 New Revision: 250963 URL: http://svnweb.freebsd.org/changeset/base/250963 Log: Driver 'aacraid' added. Supports Adaptec by PMC RAID controller families Series 6, 7, 8 and upcoming products. Older Adaptec RAID controller families are supported by the 'aac' driver. Approved by: scottl (mentor) Added: head/share/man/man4/aacraid.4 (contents, props changed) head/sys/dev/aacraid/ head/sys/dev/aacraid/aacraid.c (contents, props changed) head/sys/dev/aacraid/aacraid_cam.c (contents, props changed) head/sys/dev/aacraid/aacraid_debug.c (contents, props changed) head/sys/dev/aacraid/aacraid_debug.h (contents, props changed) head/sys/dev/aacraid/aacraid_linux.c (contents, props changed) head/sys/dev/aacraid/aacraid_pci.c (contents, props changed) head/sys/dev/aacraid/aacraid_reg.h (contents, props changed) head/sys/dev/aacraid/aacraid_var.h (contents, props changed) head/sys/modules/aacraid/ head/sys/modules/aacraid/Makefile (contents, props changed) head/sys/modules/aacraid/Makefile.inc (contents, props changed) head/sys/modules/aacraid/aacraid_linux/ head/sys/modules/aacraid/aacraid_linux/Makefile (contents, props changed) Modified: head/share/man/man4/Makefile head/sys/amd64/conf/GENERIC head/sys/amd64/conf/NOTES head/sys/conf/files head/sys/conf/options head/sys/i386/conf/GENERIC head/sys/i386/conf/NOTES head/sys/ia64/conf/GENERIC head/sys/modules/Makefile Modified: head/share/man/man4/Makefile ============================================================================== --- head/share/man/man4/Makefile Fri May 24 09:21:18 2013 (r250962) +++ head/share/man/man4/Makefile Fri May 24 09:22:43 2013 (r250963) @@ -4,6 +4,7 @@ .include MAN= aac.4 \ + aacraid.4 \ acpi.4 \ ${_acpi_asus.4} \ ${_acpi_asus_wmi.4} \ Added: head/share/man/man4/aacraid.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/aacraid.4 Fri May 24 09:22:43 2013 (r250963) @@ -0,0 +1,139 @@ +.\" Copyright (c) 2013 Achim Leubner +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.Dd April 09, 2013 +.Dt AACRAID 4 +.Os +.Sh NAME +.Nm aacraid +.Nd Adaptec AACRAID Controller driver +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd device pci +.Cd device aacraid +.Pp +To compile in debugging code: +.Cd options AACRAID_DEBUG=N +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +aacraid_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the Adaptec by PMC RAID controllers, +including Series 6/7/8 and upcoming families. +.Pp +The RAID containers are handled via the +.Nm aacraidp0 +bus. +The physical buses are represented by the +.Nm aacraidp? +devices (beginning with aacraidp1). These devices enable the +SCSI pass-thru interface and allows devices connected +to the card such as CD-ROMs to be available via the CAM +.Xr scsi 4 +subsystem. +Note that not all cards allow this interface to be enabled. +.Pp +The +.Pa /dev/aacraid? +device nodes provide access to the management interface of the controller. +One node exists per installed card. +If the kernel is compiled with the +.Dv COMPAT_LINUX +option, or the +.Pa aacraid_linux.ko +and +.Pa linux.ko +modules are loaded, the +Linux-compatible +.Xr ioctl 2 +interface for the management device will be enabled and will allow +Linux-based management applications to control the card. +.Sh HARDWARE +Controllers supported by the +.Nm +driver include: +.Pp +.Bl -bullet -compact +.It +Adaptec ASR-6405(T|E) +.It +Adaptec ASR-6445 +.It +Adaptec ASR-6805(T|E|Q|TQ) +.It +Adaptec ASR-7085 +.It +Adaptec ASR-7805(Q) +.It +Adaptec ASR-70165 +.It +Adaptec ASR-71605(E|Q) +.It +Adaptec ASR-71685 +.It +Adaptec ASR-72405 +.It +Adaptec Series 8 cards +.El +.Sh FILES +.Bl -tag -width /boot/kernel/aacraid.ko -compact +.It Pa /dev/aacraid? +aacraid management interface +.El +.Sh DIAGNOSTICS +Compiling with +.Dv AACRAID_DEBUG +set to a number between 0 and 3 +will enable increasingly verbose debug messages. +.Pp +The adapter can send status and alert messages asynchronously +to the driver. +These messages are printed on the system console, +and are also queued for retrieval by a management application. +.Sh SEE ALSO +.Xr kld 4 , +.Xr linux 4 , +.Xr scsi 4 , +.Xr kldload 8 +.Sh AUTHORS +.An Achim Leubner +.Aq achim@FreeBSD.org +.An Ed Maste +.Aq emaste@FreeBSD.org +.An Scott Long +.Aq scottl@FreeBSD.org +.Sh BUGS +.Pp +The controller is not actually paused on suspend/resume. Modified: head/sys/amd64/conf/GENERIC ============================================================================== --- head/sys/amd64/conf/GENERIC Fri May 24 09:21:18 2013 (r250962) +++ head/sys/amd64/conf/GENERIC Fri May 24 09:22:43 2013 (r250963) @@ -158,6 +158,7 @@ device tws # LSI 3ware 9750 SATA+SAS 6 # RAID controllers device aac # Adaptec FSA RAID device aacp # SCSI passthrough for aac (requires CAM) +device aacraid # Adaptec by PMC RAID device ida # Compaq Smart RAID device mfi # LSI MegaRAID SAS device mlx # Mylex DAC960 family Modified: head/sys/amd64/conf/NOTES ============================================================================== --- head/sys/amd64/conf/NOTES Fri May 24 09:21:18 2013 (r250962) +++ head/sys/amd64/conf/NOTES Fri May 24 09:22:43 2013 (r250963) @@ -406,6 +406,10 @@ device aac device aacp # SCSI Passthrough interface (optional, CAM required) # +# Adaptec by PMC RAID controllers, Series 6/7/8 and upcoming families +device aacraid # Container interface, CAM required + +# # Highpoint RocketRAID 27xx. device hpt27xx Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Fri May 24 09:21:18 2013 (r250962) +++ head/sys/conf/files Fri May 24 09:22:43 2013 (r250963) @@ -573,6 +573,11 @@ dev/aac/aac_debug.c optional aac dev/aac/aac_disk.c optional aac dev/aac/aac_linux.c optional aac compat_linux dev/aac/aac_pci.c optional aac pci +dev/aacraid/aacraid.c optional aacraid +dev/aacraid/aacraid_cam.c optional aacraid scbus +dev/aacraid/aacraid_debug.c optional aacraid +dev/aacraid/aacraid_linux.c optional aacraid compat_linux +dev/aacraid/aacraid_pci.c optional aacraid pci dev/acpi_support/acpi_wmi.c optional acpi_wmi acpi dev/acpi_support/acpi_asus.c optional acpi_asus acpi dev/acpi_support/acpi_asus_wmi.c optional acpi_asus_wmi acpi Modified: head/sys/conf/options ============================================================================== --- head/sys/conf/options Fri May 24 09:21:18 2013 (r250962) +++ head/sys/conf/options Fri May 24 09:22:43 2013 (r250963) @@ -31,6 +31,7 @@ # opt_.h AAC_DEBUG opt_aac.h +AACRAID_DEBUG opt_aacraid.h AHC_ALLOW_MEMIO opt_aic7xxx.h AHC_TMODE_ENABLE opt_aic7xxx.h AHC_DUMP_EEPROM opt_aic7xxx.h Added: head/sys/dev/aacraid/aacraid.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/aacraid/aacraid.c Fri May 24 09:22:43 2013 (r250963) @@ -0,0 +1,3501 @@ +/*- + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2001 Scott Long + * Copyright (c) 2000 BSDi + * Copyright (c) 2001-2010 Adaptec, Inc. + * Copyright (c) 2010-2012 PMC-Sierra, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Adaptec by PMC Series 6,7,8,... families of RAID controllers + */ +#define AAC_DRIVERNAME "aacraid" + +#include "opt_aacraid.h" + +/* #include */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#ifndef FILTER_HANDLED +#define FILTER_HANDLED 0x02 +#endif + +static void aac_add_container(struct aac_softc *sc, + struct aac_mntinforesp *mir, int f, + u_int32_t uid); +static void aac_get_bus_info(struct aac_softc *sc); +static void aac_container_bus(struct aac_softc *sc); +static void aac_daemon(void *arg); +static int aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, + int pages, int nseg, int nseg_new); + +/* Command Processing */ +static void aac_timeout(struct aac_softc *sc); +static void aac_command_thread(struct aac_softc *sc); +static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, + u_int32_t xferstate, struct aac_fib *fib, + u_int16_t datasize); +/* Command Buffer Management */ +static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, + int nseg, int error); +static int aac_alloc_commands(struct aac_softc *sc); +static void aac_free_commands(struct aac_softc *sc); +static void aac_unmap_command(struct aac_command *cm); + +/* Hardware Interface */ +static int aac_alloc(struct aac_softc *sc); +static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, + int error); +static int aac_check_firmware(struct aac_softc *sc); +static int aac_init(struct aac_softc *sc); +static int aac_setup_intr(struct aac_softc *sc); + +/* PMC SRC interface */ +static int aac_src_get_fwstatus(struct aac_softc *sc); +static void aac_src_qnotify(struct aac_softc *sc, int qbit); +static int aac_src_get_istatus(struct aac_softc *sc); +static void aac_src_clear_istatus(struct aac_softc *sc, int mask); +static void aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, + u_int32_t arg0, u_int32_t arg1, + u_int32_t arg2, u_int32_t arg3); +static int aac_src_get_mailbox(struct aac_softc *sc, int mb); +static void aac_src_set_interrupts(struct aac_softc *sc, int enable); +static int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm); +static int aac_src_get_outb_queue(struct aac_softc *sc); +static void aac_src_set_outb_queue(struct aac_softc *sc, int index); + +struct aac_interface aacraid_src_interface = { + aac_src_get_fwstatus, + aac_src_qnotify, + aac_src_get_istatus, + aac_src_clear_istatus, + aac_src_set_mailbox, + aac_src_get_mailbox, + aac_src_set_interrupts, + aac_src_send_command, + aac_src_get_outb_queue, + aac_src_set_outb_queue +}; + +/* PMC SRCv interface */ +static void aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, + u_int32_t arg0, u_int32_t arg1, + u_int32_t arg2, u_int32_t arg3); +static int aac_srcv_get_mailbox(struct aac_softc *sc, int mb); + +struct aac_interface aacraid_srcv_interface = { + aac_src_get_fwstatus, + aac_src_qnotify, + aac_src_get_istatus, + aac_src_clear_istatus, + aac_srcv_set_mailbox, + aac_srcv_get_mailbox, + aac_src_set_interrupts, + aac_src_send_command, + aac_src_get_outb_queue, + aac_src_set_outb_queue +}; + +/* Debugging and Diagnostics */ +static struct aac_code_lookup aac_cpu_variant[] = { + {"i960JX", CPUI960_JX}, + {"i960CX", CPUI960_CX}, + {"i960HX", CPUI960_HX}, + {"i960RX", CPUI960_RX}, + {"i960 80303", CPUI960_80303}, + {"StrongARM SA110", CPUARM_SA110}, + {"PPC603e", CPUPPC_603e}, + {"XScale 80321", CPU_XSCALE_80321}, + {"MIPS 4KC", CPU_MIPS_4KC}, + {"MIPS 5KC", CPU_MIPS_5KC}, + {"Unknown StrongARM", CPUARM_xxx}, + {"Unknown PowerPC", CPUPPC_xxx}, + {NULL, 0}, + {"Unknown processor", 0} +}; + +static struct aac_code_lookup aac_battery_platform[] = { + {"required battery present", PLATFORM_BAT_REQ_PRESENT}, + {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, + {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, + {"optional battery not installed", PLATFORM_BAT_OPT_NOTPRESENT}, + {"no battery support", PLATFORM_BAT_NOT_SUPPORTED}, + {NULL, 0}, + {"unknown battery platform", 0} +}; +static void aac_describe_controller(struct aac_softc *sc); +static char *aac_describe_code(struct aac_code_lookup *table, + u_int32_t code); + +/* Management Interface */ +static d_open_t aac_open; +static d_ioctl_t aac_ioctl; +static d_poll_t aac_poll; +#if __FreeBSD_version >= 702000 +static void aac_cdevpriv_dtor(void *arg); +#else +static d_close_t aac_close; +#endif +static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); +static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); +static void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); +static void aac_request_aif(struct aac_softc *sc); +static int aac_rev_check(struct aac_softc *sc, caddr_t udata); +static int aac_open_aif(struct aac_softc *sc, caddr_t arg); +static int aac_close_aif(struct aac_softc *sc, caddr_t arg); +static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); +static int aac_return_aif(struct aac_softc *sc, + struct aac_fib_context *ctx, caddr_t uptr); +static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); +static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); +static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); +static void aac_ioctl_event(struct aac_softc *sc, + struct aac_event *event, void *arg); +static int aac_reset_adapter(struct aac_softc *sc); +static int aac_get_container_info(struct aac_softc *sc, + struct aac_fib *fib, int cid, + struct aac_mntinforesp *mir, + u_int32_t *uid); +static u_int32_t + aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled); + +static struct cdevsw aacraid_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = aac_open, +#if __FreeBSD_version < 702000 + .d_close = aac_close, +#endif + .d_ioctl = aac_ioctl, + .d_poll = aac_poll, + .d_name = "aacraid", +}; + +MALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver"); + +/* sysctl node */ +SYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD, 0, "AACRAID driver parameters"); + +/* + * Device Interface + */ + +/* + * Initialize the controller and softc + */ +int +aacraid_attach(struct aac_softc *sc) +{ + int error, unit; + struct aac_fib *fib; + struct aac_mntinforesp mir; + int count = 0, i = 0; + u_int32_t uid; + + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + sc->hint_flags = device_get_flags(sc->aac_dev); + /* + * Initialize per-controller queues. + */ + aac_initq_free(sc); + aac_initq_ready(sc); + aac_initq_busy(sc); + + /* mark controller as suspended until we get ourselves organised */ + sc->aac_state |= AAC_STATE_SUSPEND; + + /* + * Check that the firmware on the card is supported. + */ + if ((error = aac_check_firmware(sc)) != 0) + return(error); + + /* + * Initialize locks + */ + mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF); + TAILQ_INIT(&sc->aac_container_tqh); + TAILQ_INIT(&sc->aac_ev_cmfree); + +#if __FreeBSD_version >= 800000 + /* Initialize the clock daemon callout. */ + callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); +#endif + /* + * Initialize the adapter. + */ + if ((error = aac_alloc(sc)) != 0) + return(error); + if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { + if ((error = aac_init(sc)) != 0) + return(error); + } + + /* + * Allocate and connect our interrupt. + */ + if ((error = aac_setup_intr(sc)) != 0) + return(error); + + /* + * Print a little information about the controller. + */ + aac_describe_controller(sc); + + /* + * Make the control device. + */ + unit = device_get_unit(sc->aac_dev); + sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR, + 0640, "aacraid%d", unit); + sc->aac_dev_t->si_drv1 = sc; + + /* Create the AIF thread */ + if (aac_kthread_create((void(*)(void *))aac_command_thread, sc, + &sc->aifthread, 0, 0, "aacraid%daif", unit)) + panic("Could not create AIF thread"); + + /* Register the shutdown method to only be called post-dump */ + if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown, + sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) + device_printf(sc->aac_dev, + "shutdown event registration failed\n"); + + /* Find containers */ + mtx_lock(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); + /* loop over possible containers */ + do { + if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0) + continue; + if (i == 0) + count = mir.MntRespCount; + aac_add_container(sc, &mir, 0, uid); + i++; + } while ((i < count) && (i < AAC_MAX_CONTAINERS)); + aac_release_sync_fib(sc); + mtx_unlock(&sc->aac_io_lock); + + /* Register with CAM for the containers */ + TAILQ_INIT(&sc->aac_sim_tqh); + aac_container_bus(sc); + /* Register with CAM for the non-DASD devices */ + if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) + aac_get_bus_info(sc); + + /* poke the bus to actually attach the child devices */ + bus_generic_attach(sc->aac_dev); + + /* mark the controller up */ + sc->aac_state &= ~AAC_STATE_SUSPEND; + + /* enable interrupts now */ + AAC_UNMASK_INTERRUPTS(sc); + +#if __FreeBSD_version >= 800000 + mtx_lock(&sc->aac_io_lock); + callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); + mtx_unlock(&sc->aac_io_lock); +#else + { + struct timeval tv; + tv.tv_sec = 60; + tv.tv_usec = 0; + sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); + } +#endif + + return(0); +} + +static void +aac_daemon(void *arg) +{ + struct aac_softc *sc; + struct timeval tv; + struct aac_command *cm; + struct aac_fib *fib; + + sc = arg; + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + +#if __FreeBSD_version >= 800000 + mtx_assert(&sc->aac_io_lock, MA_OWNED); + if (callout_pending(&sc->aac_daemontime) || + callout_active(&sc->aac_daemontime) == 0) + return; +#else + mtx_lock(&sc->aac_io_lock); +#endif + getmicrotime(&tv); + + if (!aacraid_alloc_command(sc, &cm)) { + fib = cm->cm_fib; + cm->cm_timestamp = time_uptime; + cm->cm_datalen = 0; + cm->cm_flags |= AAC_CMD_WAIT; + + fib->Header.Size = + sizeof(struct aac_fib_header) + sizeof(u_int32_t); + fib->Header.XferState = + AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | + AAC_FIBSTATE_EMPTY | + AAC_FIBSTATE_FROMHOST | + AAC_FIBSTATE_REXPECTED | + AAC_FIBSTATE_NORM | + AAC_FIBSTATE_ASYNC | + AAC_FIBSTATE_FAST_RESPONSE; + fib->Header.Command = SendHostTime; + *(uint32_t *)fib->data = tv.tv_sec; + + aacraid_map_command_sg(cm, NULL, 0, 0); + aacraid_release_command(cm); + } + +#if __FreeBSD_version >= 800000 + callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); +#else + mtx_unlock(&sc->aac_io_lock); + tv.tv_sec = 30 * 60; + tv.tv_usec = 0; + sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); +#endif +} + +void +aacraid_add_event(struct aac_softc *sc, struct aac_event *event) +{ + + switch (event->ev_type & AAC_EVENT_MASK) { + case AAC_EVENT_CMFREE: + TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); + break; + default: + device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", + event->ev_type); + break; + } + + return; +} + +/* + * Request information of container #cid + */ +static int +aac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid, + struct aac_mntinforesp *mir, u_int32_t *uid) +{ + struct aac_command *cm; + struct aac_fib *fib; + struct aac_mntinfo *mi; + struct aac_cnt_config *ccfg; + + if (sync_fib == NULL) { + if (aacraid_alloc_command(sc, &cm)) { + device_printf(sc->aac_dev, + "Warning, no free command available\n"); + return (-1); + } + fib = cm->cm_fib; + } else { + fib = sync_fib; + } + + mi = (struct aac_mntinfo *)&fib->data[0]; + /* 4KB support?, 64-bit LBA? */ + if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE) + mi->Command = VM_NameServeAllBlk; + else if (sc->flags & AAC_FLAGS_LBA_64BIT) + mi->Command = VM_NameServe64; + else + mi->Command = VM_NameServe; + mi->MntType = FT_FILESYS; + mi->MntCount = cid; + + if (sync_fib) { + if (aac_sync_fib(sc, ContainerCommand, 0, fib, + sizeof(struct aac_mntinfo))) { + device_printf(sc->aac_dev, "Error probing container %d\n", cid); + return (-1); + } + } else { + cm->cm_timestamp = time_uptime; + cm->cm_datalen = 0; + + fib->Header.Size = + sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo); + fib->Header.XferState = + AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | + AAC_FIBSTATE_EMPTY | + AAC_FIBSTATE_FROMHOST | + AAC_FIBSTATE_REXPECTED | + AAC_FIBSTATE_NORM | + AAC_FIBSTATE_ASYNC | + AAC_FIBSTATE_FAST_RESPONSE; + fib->Header.Command = ContainerCommand; + if (aacraid_wait_command(cm) != 0) { + device_printf(sc->aac_dev, "Error probing container %d\n", cid); + aacraid_release_command(cm); + return (-1); + } + } + bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp)); + + /* UID */ + *uid = cid; + if (mir->MntTable[0].VolType != CT_NONE && + !(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) { + if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) + mir->MntTable[0].ObjExtension.BlockSize = 0x200; + + ccfg = (struct aac_cnt_config *)&fib->data[0]; + bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); + ccfg->Command = VM_ContainerConfig; + ccfg->CTCommand.command = CT_CID_TO_32BITS_UID; + ccfg->CTCommand.param[0] = cid; + + if (sync_fib) { + if (aac_sync_fib(sc, ContainerCommand, 0, fib, + sizeof(struct aac_cnt_config) == 0) && + ccfg->CTCommand.param[0] == ST_OK && + mir->MntTable[0].VolType != CT_PASSTHRU) + *uid = ccfg->CTCommand.param[1]; + } else { + fib->Header.Size = + sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); + fib->Header.XferState = + AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | + AAC_FIBSTATE_EMPTY | + AAC_FIBSTATE_FROMHOST | + AAC_FIBSTATE_REXPECTED | + AAC_FIBSTATE_NORM | + AAC_FIBSTATE_ASYNC | + AAC_FIBSTATE_FAST_RESPONSE; + fib->Header.Command = ContainerCommand; + if (aacraid_wait_command(cm) == 0 && + ccfg->CTCommand.param[0] == ST_OK && + mir->MntTable[0].VolType != CT_PASSTHRU) + *uid = ccfg->CTCommand.param[1]; + aacraid_release_command(cm); + } + } + + return (0); +} + +/* + * Create a device to represent a new container + */ +static void +aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f, + u_int32_t uid) +{ + struct aac_container *co; + + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + + /* + * Check container volume type for validity. Note that many of + * the possible types may never show up. + */ + if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { + co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF, + M_NOWAIT | M_ZERO); + if (co == NULL) { + panic("Out of memory?!"); + } + + co->co_found = f; + bcopy(&mir->MntTable[0], &co->co_mntobj, + sizeof(struct aac_mntobj)); + co->co_uid = uid; + TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); + } +} + +/* + * Allocate resources associated with (sc) + */ +static int +aac_alloc(struct aac_softc *sc) +{ + bus_size_t maxsize; + + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + + /* + * Create DMA tag for mapping buffers into controller-addressable space. + */ + if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + (sc->flags & AAC_FLAGS_SG_64BIT) ? + BUS_SPACE_MAXADDR : + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAXBSIZE, /* maxsize */ + sc->aac_sg_tablesize, /* nsegments */ + MAXBSIZE, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->aac_io_lock, /* lockfuncarg */ + &sc->aac_buffer_dmat)) { + device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); + return (ENOMEM); + } + + /* + * Create DMA tag for mapping FIBs into controller-addressable space.. + */ + if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) + maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + + sizeof(struct aac_fib_xporthdr) + 31); + else + maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31); + if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + (sc->flags & AAC_FLAGS_4GB_WINDOW) ? + BUS_SPACE_MAXADDR_32BIT : + 0x7fffffff, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + maxsize, /* maxsize */ + 1, /* nsegments */ + maxsize, /* maxsize */ + 0, /* flags */ + NULL, NULL, /* No locking needed */ + &sc->aac_fib_dmat)) { + device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); + return (ENOMEM); + } + + /* + * Create DMA tag for the common structure and allocate it. + */ + maxsize = sizeof(struct aac_common); + maxsize += sc->aac_max_fibs * sizeof(u_int32_t); + if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + (sc->flags & AAC_FLAGS_4GB_WINDOW) ? + BUS_SPACE_MAXADDR_32BIT : + 0x7fffffff, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + maxsize, /* maxsize */ + 1, /* nsegments */ + maxsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* No locking needed */ + &sc->aac_common_dmat)) { + device_printf(sc->aac_dev, + "can't allocate common structure DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, + BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { + device_printf(sc->aac_dev, "can't allocate common structure\n"); + return (ENOMEM); + } + + (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, + sc->aac_common, maxsize, + aac_common_map, sc, 0); + bzero(sc->aac_common, maxsize); + + /* Allocate some FIBs and associated command structs */ + TAILQ_INIT(&sc->aac_fibmap_tqh); + sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), + M_AACRAIDBUF, M_WAITOK|M_ZERO); + mtx_lock(&sc->aac_io_lock); + while (sc->total_fibs < sc->aac_max_fibs) { + if (aac_alloc_commands(sc) != 0) + break; + } + mtx_unlock(&sc->aac_io_lock); + if (sc->total_fibs == 0) + return (ENOMEM); + + return (0); +} + +/* + * Free all of the resources associated with (sc) + * + * Should not be called if the controller is active. + */ +void +aacraid_free(struct aac_softc *sc) +{ + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + + /* remove the control device */ + if (sc->aac_dev_t != NULL) + destroy_dev(sc->aac_dev_t); + + /* throw away any FIB buffers, discard the FIB DMA tag */ + aac_free_commands(sc); + if (sc->aac_fib_dmat) + bus_dma_tag_destroy(sc->aac_fib_dmat); + + free(sc->aac_commands, M_AACRAIDBUF); + + /* destroy the common area */ + if (sc->aac_common) { + bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); + bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, + sc->aac_common_dmamap); + } + if (sc->aac_common_dmat) + bus_dma_tag_destroy(sc->aac_common_dmat); + + /* disconnect the interrupt handler */ + if (sc->aac_intr) + bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); + if (sc->aac_irq != NULL) + bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, + sc->aac_irq); + + /* destroy data-transfer DMA tag */ + if (sc->aac_buffer_dmat) + bus_dma_tag_destroy(sc->aac_buffer_dmat); + + /* destroy the parent DMA tag */ + if (sc->aac_parent_dmat) + bus_dma_tag_destroy(sc->aac_parent_dmat); + + /* release the register window mapping */ + if (sc->aac_regs_res0 != NULL) + bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, + sc->aac_regs_rid0, sc->aac_regs_res0); + if (sc->aac_regs_res1 != NULL) + bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, + sc->aac_regs_rid1, sc->aac_regs_res1); +} + +/* + * Disconnect from the controller completely, in preparation for unload. + */ +int +aacraid_detach(device_t dev) +{ + struct aac_softc *sc; + struct aac_container *co; + struct aac_sim *sim; + int error; + + sc = device_get_softc(dev); + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + +#if __FreeBSD_version >= 800000 + callout_drain(&sc->aac_daemontime); +#else + untimeout(aac_daemon, (void *)sc, sc->timeout_id); +#endif + /* Remove the child containers */ + while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { + TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); + free(co, M_AACRAIDBUF); + } + + /* Remove the CAM SIMs */ + while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { + TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); + error = device_delete_child(dev, sim->sim_dev); + if (error) + return (error); + free(sim, M_AACRAIDBUF); + } + + if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { + sc->aifflags |= AAC_AIFFLAGS_EXIT; + wakeup(sc->aifthread); + tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz); + } + + if (sc->aifflags & AAC_AIFFLAGS_RUNNING) + panic("Cannot shutdown AIF thread"); + + if ((error = aacraid_shutdown(dev))) + return(error); + + EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); + + aacraid_free(sc); + + mtx_destroy(&sc->aac_io_lock); + + return(0); +} + +/* + * Bring the controller down to a dormant state and detach all child devices. + * + * This function is called before detach or system shutdown. + * + * Note that we can assume that the bioq on the controller is empty, as we won't + * allow shutdown if any device is open. + */ +int +aacraid_shutdown(device_t dev) +{ + struct aac_softc *sc; + struct aac_fib *fib; + struct aac_close_command *cc; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***