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 <bsd.own.mk>
 
 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 ac...@freebsd.org
+.An Ed Maste
+.Aq ema...@freebsd.org
+.An Scott Long
+.Aq sco...@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_<name-of-option-in-lower-case>.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 <sys/cdefs.h>
+__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 <stddef.h> */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/sysctl.h>
+#include <sys/poll.h>
+#include <sys/ioccom.h>
+
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/signalvar.h>
+#include <sys/time.h>
+#include <sys/eventhandler.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <sys/bus_dma.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/aacraid/aacraid_reg.h>
+#include <sys/aac_ioctl.h>
+#include <dev/aacraid/aacraid_debug.h>
+#include <dev/aacraid/aacraid_var.h>
+
+#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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to