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

Achim Leubner achim at FreeBSD.org
Fri May 24 09:22:44 UTC 2013


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 achim at FreeBSD.org
+.An Ed Maste
+.Aq emaste at FreeBSD.org
+.An Scott Long
+.Aq scottl at 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 ***


More information about the svn-src-all mailing list