.\" (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: src/share/man/man4/amr.4,v 1.3.2.10 2003/05/26 12:41:05 hmp Exp $
+.\" $FreeBSD: src/share/man/man4/amr.4,v 1.35 2006/06/18 14:45:28 brueffer Exp $
.\"
-.Dd November 30, 2010
+.Dd December 3, 2010
.Dt AMR 4
.Os
.Sh NAME
.Nm amr
-.Nd AMI MegaRAID PCI-SCSI RAID driver
+.Nd MegaRAID SCSI/ATA/SATA RAID driver
.Sh SYNOPSIS
-.Cd device pci
-.Cd device amr
+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 scbus"
+.Cd "device amr"
+.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
+amr_load="YES"
+.Ed
.Sh DESCRIPTION
The
.Nm
-driver provides support for American Megatrends MegaRAID Express,
-Elite and Enterprise family SCSI RAID controllers,
-including models relabeled and sold by Hewlett-Packard and Dell.
+driver provides support for LSI Logic MegaRAID SCSI, ATA and SATA
+RAID controllers and legacy American Megatrends MegaRAID
+SCSI RAID controllers, including models relabeled
+and sold by Dell and Hewlett-Packard.
.Pp
LSI MegaRAID SAS controllers are supported by
.Xr mfi 4
and will not work with this driver.
+.Sh HARDWARE
+Controllers supported by the
+.Nm
+driver include:
.Pp
-Supported controllers include:
-.Bl -bullet
+.Bl -bullet -compact
+.It
+MegaRAID SATA 150-4
+.It
+MegaRAID SATA 150-6
+.It
+MegaRAID SATA 300-4X
+.It
+MegaRAID SATA 300-8X
+.It
+MegaRAID SCSI 320-1E
+.It
+MegaRAID SCSI 320-2E
+.It
+MegaRAID SCSI 320-4E
.It
-MegaRAID 320-1
+MegaRAID SCSI 320-0X
.It
-MegaRAID 320-2
+MegaRAID SCSI 320-2X
+.It
+MegaRAID SCSI 320-4X
+.It
+MegaRAID SCSI 320-0
+.It
+MegaRAID SCSI 320-1
+.It
+MegaRAID SCSI 320-2
+.It
+MegaRAID SCSI 320-4
.It
MegaRAID Series 418
.It
+MegaRAID i4 133 RAID
+.It
+MegaRAID Elite 1500 (Series 467)
+.It
+MegaRAID Elite 1600 (Series 493)
+.It
+MegaRAID Elite 1650 (Series 4xx)
+.It
MegaRAID Enterprise 1200 (Series 428)
.It
MegaRAID Enterprise 1300 (Series 434)
.It
MegaRAID Enterprise 1600 (Series 471)
.It
-MegaRAID Elite 1500 (Series 467)
-.It
-MegaRAID Elite 1600 (Series 493)
-.It
MegaRAID Express 100 (Series 466WS)
.It
MegaRAID Express 200 (Series 466)
.It
Dell PERC 2/DC
.It
+Dell PERC 3/DCL
+.It
+Dell PERC 3/QC
+.It
+Dell PERC 4/DC
+.It
+Dell PERC 4/IM
+.It
+Dell PERC 4/SC
+.It
+Dell PERC 4/Di
+.It
+Dell PERC 4e/DC
+.It
+Dell PERC 4e/Di
+.It
+Dell PERC 4e/Si
+.It
+Dell PERC 4ei
+.It
HP NetRAID-1/Si
.It
-HP NetRAID-3/Si
+HP NetRAID-3/Si (D4943A)
.It
HP Embedded NetRAID
+.It
+Intel RAID Controller SRCS16
+.It
+Intel RAID Controller SRCU42X
.El
.Sh DIAGNOSTICS
.Ss Driver initialisation/shutdown phase
The
.Nm
driver was written by
-.An Mike Smith
-.Aq msmith@FreeBSD.org .
+.An Mike Smith Aq msmith@FreeBSD.org .
.Pp
This manual page was written by
-.An Mike Smith
-.Aq msmith@FreeBSD.org
+.An Mike Smith Aq msmith@FreeBSD.org
and
-.An Jeroen Ruigrok van der Werven
-.Aq asmodai@FreeBSD.org .
+.An Jeroen Ruigrok van der Werven Aq asmodai@FreeBSD.org .
dev/disk/nata/atapi-cd.c optional natapicd
dev/disk/nata/atapi-fd.c optional natapifd
dev/disk/nata/atapi-tape.c optional natapist
-dev/raid/amr/amr_cam.c optional amr
-dev/raid/amr/amr_disk.c optional amr
-dev/raid/amr/amr_pci.c optional amr
dev/raid/amr/amr.c optional amr
+dev/raid/amr/amr_cam.c optional amrp amr
+dev/raid/amr/amr_disk.c optional amr
+#dev/raid/amr/amr_linux.c optional amr compat_linux
+dev/raid/amr/amr_pci.c optional amr pci
dev/disk/aha/aha.c optional aha
dev/disk/aha/aha_isa.c optional aha isa
dev/disk/ahb/ahb.c optional ahb eisa
device ida # Compaq Smart RAID
device ips # IBM ServeRAID
device amr # AMI MegaRAID
+device amrp # SCSI Passthrough interface (optional, CAM req.)
device mlx # Mylex DAC960 family
device mfi # LSI MegaRAID SAS
device mfip # LSI MegaRAID SAS passthrough, requires CAM
device ida # Compaq Smart RAID
device ips # IBM ServeRAID
device amr # AMI MegaRAID
+device amrp # SCSI Passthrough interface (optional, CAM req.)
device mlx # Mylex DAC960 family
device mfi # LSI MegaRAID SAS
device mfip # LSI MegaRAID SAS passthrough, requires CAM
device ida # Compaq Smart RAID
device mlx # Mylex DAC960
device amr # AMI MegaRAID
+device amrp # SCSI Passthrough interface (optional, CAM req.)
device mfi # LSI MegaRAID SAS
device mfip # LSI MegaRAID SAS passthrough, requires CAM
options MFI_DEBUG
device ida # Compaq Smart RAID
device ips # IBM ServeRAID
device amr # AMI MegaRAID
+device amrp # SCSI Passthrough interface (optional, CAM req.)
device mlx # Mylex DAC960 family
device mfi # LSI MegaRAID SAS
device mfip # LSI MegaRAID SAS passthrough, requires CAM
device ida # Compaq Smart RAID
device ips # IBM ServeRAID
device amr # AMI MegaRAID
+device amrp # SCSI Passthrough interface (optional, CAM req.)
device mlx # Mylex DAC960 family
device mfi # LSI MegaRAID SAS
device mfip # LSI MegaRAID SAS passthrough, requires CAM
-# $FreeBSD: src/sys/modules/amr/Makefile,v 1.4.2.2 2002/10/28 21:10:06 emoore Exp $
+# $FreeBSD: src/sys/modules/amr/Makefile,v 1.14 2010/08/23 06:13:29 imp Exp $
-KMOD = amr
-SRCS = amr.c amr_pci.c amr_disk.c device_if.h bus_if.h pci_if.h
+SUBDIR= amr_cam
+#.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
+#SUBDIR+= amr_linux
+#.endif
-# SCSI passthrough support for non-disk devices
-#CFLAGS += -DAMR_SCSI_PASSTHROUGH
-SRCS += amr_cam.c opt_cam.h opt_scsi.h
+KMOD= amr
+SRCS= amr.c amr_pci.c amr_disk.c device_if.h bus_if.h pci_if.h
# Enable a questionable optimisation for newer adapters
-#CFLAGS += -DAMR_QUARTZ_GOFASTER
+#CFLAGS+= -DAMR_QUARTZ_GOFASTER
# Debugging
-#CFLAGS += -DAMR_DEBUG=3
+#CFLAGS+= -DAMR_DEBUG=3
.include <bsd.kmod.mk>
/*-
* Copyright (c) 1999,2000 Michael Smith
* Copyright (c) 2000 BSDi
+ * Copyright (c) 2005 Scott Long
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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.
- *
+ */
+/*-
* Copyright (c) 2002 Eric Moore
- * Copyright (c) 2002 LSI Logic Corporation
+ * Copyright (c) 2002, 2004 LSI Logic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amr.c,v 1.7.2.13 2003/01/15 13:41:18 emoore Exp $
+ * $FreeBSD: src/sys/dev/amr/amr.c,v 1.95 2010/01/07 21:01:37 mbr Exp $
*/
/*
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/sysmsg.h>
-#include "amr_compat.h"
+#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/devicestat.h>
-#include <sys/disk.h>
#include <sys/stat.h>
+
+#include <machine/cpu.h>
#include <sys/rman.h>
#include <bus/pci/pcireg.h>
#include <bus/pci/pcivar.h>
-#include "amrio.h"
-#include "amrreg.h"
-#include "amrvar.h"
+#include <dev/raid/amr/amrio.h>
+#include <dev/raid/amr/amrreg.h>
+#include <dev/raid/amr/amrvar.h>
#define AMR_DEFINE_TABLES
-#include "amr_tables.h"
+#include <dev/raid/amr/amr_tables.h>
+
+SYSCTL_NODE(_hw, OID_AUTO, amr, CTLFLAG_RD, 0, "AMR driver parameters");
static d_open_t amr_open;
static d_close_t amr_close;
{ "amr", 0, 0 },
.d_open = amr_open,
.d_close = amr_close,
- .d_ioctl = amr_ioctl
+ .d_ioctl = amr_ioctl,
};
+int linux_no_adapter = 0;
/*
* Initialisation, bus interface.
*/
*/
static int amr_query_controller(struct amr_softc *sc);
static void *amr_enquiry(struct amr_softc *sc, size_t bufsize,
- u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual);
+ u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual, int *status);
static void amr_completeio(struct amr_command *ac);
static int amr_support_ext_cdb(struct amr_softc *sc);
* Command processing.
*/
static int amr_bio_command(struct amr_softc *sc, struct amr_command **acp);
-static int amr_wait_command(struct amr_command *ac);
-static int amr_getslot(struct amr_command *ac);
-static void amr_mapcmd(struct amr_command *ac);
+static int amr_wait_command(struct amr_command *ac) __unused;
+static int amr_mapcmd(struct amr_command *ac);
static void amr_unmapcmd(struct amr_command *ac);
static int amr_start(struct amr_command *ac);
-static void amr_complete(void *context, int pending);
+static void amr_complete(void *context, ac_qhead_t *head);
+static void amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
+static void amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
+static void amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
+static void amr_abort_load(struct amr_command *ac);
/*
* Status monitoring
/*
* Interface-specific shims
*/
-static int amr_quartz_submit_command(struct amr_softc *sc);
+static int amr_quartz_submit_command(struct amr_command *ac);
static int amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
static int amr_quartz_poll_command(struct amr_command *ac);
+static int amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac);
-static int amr_std_submit_command(struct amr_softc *sc);
+static int amr_std_submit_command(struct amr_command *ac);
static int amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave);
static int amr_std_poll_command(struct amr_command *ac);
static void amr_std_attach_mailbox(struct amr_softc *sc);
#endif
#endif
-DECLARE_DUMMY_MODULE(amr);
+static void amr_init_sysctl(struct amr_softc *sc);
+static int amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr,
+ int32_t flag, struct sysmsg *sm);
+
+MALLOC_DEFINE(M_AMR, "amr", "AMR memory");
/********************************************************************************
********************************************************************************
int
amr_attach(struct amr_softc *sc)
{
+ device_t child;
debug_called(1);
/*
* Initialise per-controller queues.
*/
- TAILQ_INIT(&sc->amr_completed);
- TAILQ_INIT(&sc->amr_freecmds);
+ amr_init_qhead(&sc->amr_freecmds);
+ amr_init_qhead(&sc->amr_ready);
TAILQ_INIT(&sc->amr_cmd_clusters);
- TAILQ_INIT(&sc->amr_ready);
bioq_init(&sc->amr_bioq);
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
- /*
- * Initialise command-completion task.
- */
- TASK_INIT(&sc->amr_task_complete, 0, amr_complete, sc);
-#endif
-
debug(2, "queue init done");
/*
sc->amr_submit_command = amr_quartz_submit_command;
sc->amr_get_work = amr_quartz_get_work;
sc->amr_poll_command = amr_quartz_poll_command;
+ sc->amr_poll_command1 = amr_quartz_poll_command1;
} else {
sc->amr_submit_command = amr_std_submit_command;
sc->amr_get_work = amr_std_get_work;
}
#ifdef AMR_BOARD_INIT
- if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc))))
+ if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc)))
return(ENXIO);
#endif
/*
+ * Allocate initial commands.
+ */
+ amr_alloccmd_cluster(sc);
+
+ /*
* Quiz controller for features and limits.
*/
if (amr_query_controller(sc))
debug(2, "controller query complete");
/*
+ * preallocate the remaining commands.
+ */
+ while (sc->amr_nextslot < sc->amr_maxio)
+ amr_alloccmd_cluster(sc);
+
+ /*
+ * Setup sysctls.
+ */
+ sysctl_ctx_init(&sc->amr_sysctl_ctx);
+ sc->amr_sysctl_tree = SYSCTL_ADD_NODE(&sc->amr_sysctl_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
+ device_get_nameunit(sc->amr_dev), CTLFLAG_RD, 0, "");
+ if (sc->amr_sysctl_tree == NULL) {
+ device_printf(sc->amr_dev, "can't add sysctl node\n");
+ return (EINVAL);
+ }
+ amr_init_sysctl(sc);
+
+ /*
* Attach our 'real' SCSI channels to CAM.
*/
- if (amr_cam_attach(sc))
- return(ENXIO);
- debug(2, "CAM attach done");
+ child = device_add_child(sc->amr_dev, "amrp", -1);
+ sc->amr_pass = child;
+ if (child != NULL) {
+ device_set_softc(child, sc);
+ device_set_desc(child, "SCSI Passthrough Bus");
+ bus_generic_attach(sc->amr_dev);
+ }
/*
* Create the control device.
*/
- sc->amr_dev_t = make_dev(&amr_ops, device_get_unit(sc->amr_dev),
- UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR,
- "amr%d", device_get_unit(sc->amr_dev));
+ sc->amr_dev_t = make_dev(&amr_ops, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR,
+ S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev));
sc->amr_dev_t->si_drv1 = sc;
- reference_dev(sc->amr_dev_t);
+ linux_no_adapter++;
+ if (device_get_unit(sc->amr_dev) == 0)
+ make_dev_alias(sc->amr_dev_t, "megadev0");
/*
* Schedule ourselves to bring the controller up once interrupts are
bzero(&sc->amr_ich, sizeof(struct intr_config_hook));
sc->amr_ich.ich_func = amr_startup;
sc->amr_ich.ich_arg = sc;
- sc->amr_ich.ich_desc = "amr";
if (config_intrhook_establish(&sc->amr_ich) != 0) {
device_printf(sc->amr_dev, "can't establish configuration hook\n");
return(ENOMEM);
callout_init(&sc->amr_timeout);
/* pull ourselves off the intrhook chain */
- config_intrhook_disestablish(&sc->amr_ich);
+ if (sc->amr_ich.ich_func)
+ config_intrhook_disestablish(&sc->amr_ich);
+ sc->amr_ich.ich_func = NULL;
/* get up-to-date drive information */
if (amr_query_controller(sc)) {
/*
* Start the timeout routine.
*/
-/* callout_reset(&sc->amr_timeout, hz, amr_periodic, sc); */
+/* sc->amr_timeout = timeout(amr_periodic, sc, hz);*/
return;
}
+static void
+amr_init_sysctl(struct amr_softc *sc)
+{
+
+ SYSCTL_ADD_INT(&sc->amr_sysctl_ctx,
+ SYSCTL_CHILDREN(sc->amr_sysctl_tree),
+ OID_AUTO, "allow_volume_configure", CTLFLAG_RW, &sc->amr_allow_vol_config, 0,
+ "");
+ SYSCTL_ADD_INT(&sc->amr_sysctl_ctx,
+ SYSCTL_CHILDREN(sc->amr_sysctl_tree),
+ OID_AUTO, "nextslot", CTLFLAG_RD, &sc->amr_nextslot, 0,
+ "");
+ SYSCTL_ADD_INT(&sc->amr_sysctl_ctx,
+ SYSCTL_CHILDREN(sc->amr_sysctl_tree),
+ OID_AUTO, "busyslots", CTLFLAG_RD, &sc->amr_busyslots, 0,
+ "");
+ SYSCTL_ADD_INT(&sc->amr_sysctl_ctx,
+ SYSCTL_CHILDREN(sc->amr_sysctl_tree),
+ OID_AUTO, "maxio", CTLFLAG_RD, &sc->amr_maxio, 0,
+ "");
+}
+
+
/*******************************************************************************
* Free resources associated with a controller instance
*/
struct amr_command_cluster *acc;
/* detach from CAM */
- amr_cam_detach(sc);
+ if (sc->amr_pass != NULL)
+ device_delete_child(sc->amr_dev, sc->amr_pass);
/* cancel status timeout */
callout_stop(&sc->amr_timeout);
}
/* destroy control device */
- if( sc->amr_dev_t != (cdev_t)NULL)
+ if(sc->amr_dev_t != (struct cdev *)NULL)
destroy_dev(sc->amr_dev_t);
dev_ops_remove_minor(&amr_ops, device_get_unit(sc->amr_dev));
+
+#if 0 /* XXX swildner */
+ if (mtx_initialized(&sc->amr_hw_lock))
+ mtx_destroy(&sc->amr_hw_lock);
+
+ if (mtx_initialized(&sc->amr_list_lock))
+ mtx_destroy(&sc->amr_list_lock);
+#endif
+
+ if (sc->amr_sysctl_tree != NULL)
+ sysctl_ctx_free(&sc->amr_sysctl_ctx);
+
+ lockuninit(&sc->amr_hw_lock);
+ lockuninit(&sc->amr_list_lock);
}
/*******************************************************************************
{
debug_called(2);
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
amr_enqueue_bio(sc, bio);
amr_startio(sc);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
return(0);
}
static int
amr_open(struct dev_open_args *ap)
{
- cdev_t dev = ap->a_head.a_dev;
+ cdev_t dev = ap->a_head.a_dev;
int unit = minor(dev);
struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit);
return(0);
}
+#ifdef LSI
+static int
+amr_del_ld(struct amr_softc *sc, int drv_no, int status)
+{
+
+ debug_called(1);
+
+ sc->amr_state &= ~AMR_STATE_QUEUE_FRZN;
+ sc->amr_state &= ~AMR_STATE_LD_DELETE;
+ sc->amr_state |= AMR_STATE_REMAP_LD;
+ debug(1, "State Set");
+
+ if (!status) {
+ debug(1, "disk begin destroyed %d",drv_no);
+ if (--amr_disks_registered == 0)
+ cdevsw_remove(&amrddisk_cdevsw);
+ debug(1, "disk begin destroyed success");
+ }
+ return 0;
+}
+
+static int
+amr_prepare_ld_delete(struct amr_softc *sc)
+{
+
+ debug_called(1);
+ if (sc->ld_del_supported == 0)
+ return(ENOIOCTL);
+
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
+ sc->amr_state |= AMR_STATE_LD_DELETE;
+
+ /* 5 minutes for the all the commands to be flushed.*/
+ tsleep((void *)&sc->ld_del_supported, PCATCH,"delete_logical_drv",hz * 60 * 1);
+ if ( sc->amr_busyslots )
+ return(ENOIOCTL);
+
+ return 0;
+}
+#endif
+
/********************************************************************************
* Accept the last close on the control device.
*/
static int
amr_close(struct dev_close_args *ap)
{
- cdev_t dev = ap->a_head.a_dev;
+ cdev_t dev = ap->a_head.a_dev;
int unit = minor(dev);
struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit);
/********************************************************************************
* Handle controller-specific control operations.
*/
+static void
+amr_rescan_drives(struct cdev *dev)
+{
+ struct amr_softc *sc = (struct amr_softc *)dev->si_drv1;
+ int i, error = 0;
+
+ sc->amr_state |= AMR_STATE_REMAP_LD;
+ while (sc->amr_busyslots) {
+ device_printf(sc->amr_dev, "idle controller\n");
+ amr_done(sc);
+ }
+
+ /* mark ourselves as in-shutdown */
+ sc->amr_state |= AMR_STATE_SHUTDOWN;
+
+ /* flush controller */
+ device_printf(sc->amr_dev, "flushing cache...");
+ kprintf("%s\n", amr_flush(sc) ? "failed" : "done");
+
+ /* delete all our child devices */
+ for(i = 0 ; i < AMR_MAXLD; i++) {
+ if(sc->amr_drive[i].al_disk != 0) {
+ if((error = device_delete_child(sc->amr_dev,
+ sc->amr_drive[i].al_disk)) != 0)
+ goto shutdown_out;
+
+ sc->amr_drive[i].al_disk = 0;
+ }
+ }
+
+shutdown_out:
+ amr_startup(sc);
+}
+
+int
+amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag,
+ struct sysmsg *sm)
+{
+ struct amr_softc *sc = (struct amr_softc *)dev->si_drv1;
+ struct amr_command *ac;
+ struct amr_mailbox *mb;
+ struct amr_linux_ioctl ali;
+ void *dp, *temp;
+ int error;
+ int adapter, len, ac_flags = 0;
+ int logical_drives_changed = 0;
+ u_int32_t linux_version = 0x02100000;
+ u_int8_t status;
+ struct amr_passthrough *ap; /* 60 bytes */
+
+ error = 0;
+ dp = NULL;
+ ac = NULL;
+ ap = NULL;
+
+ if ((error = copyin(addr, &ali, sizeof(ali))) != 0)
+ return (error);
+ switch (ali.ui.fcs.opcode) {
+ case 0x82:
+ switch(ali.ui.fcs.subopcode) {
+ case 'e':
+ copyout(&linux_version, (void *)(uintptr_t)ali.data,
+ sizeof(linux_version));
+ error = 0;
+ break;
+
+ case 'm':
+ copyout(&linux_no_adapter, (void *)(uintptr_t)ali.data,
+ sizeof(linux_no_adapter));
+ sm->sm_result.iresult = linux_no_adapter;
+ error = 0;
+ break;
+
+ default:
+ kprintf("Unknown subopcode\n");
+ error = ENOIOCTL;
+ break;
+ }
+ break;
+
+ case 0x80:
+ case 0x81:
+ if (ali.ui.fcs.opcode == 0x80)
+ len = max(ali.outlen, ali.inlen);
+ else
+ len = ali.ui.fcs.length;
+
+ adapter = (ali.ui.fcs.adapno) ^ 'm' << 8;
+
+ mb = (void *)&ali.mbox[0];
+
+ if ((ali.mbox[0] == FC_DEL_LOGDRV && ali.mbox[2] == OP_DEL_LOGDRV) || /* delete */
+ (ali.mbox[0] == AMR_CMD_CONFIG && ali.mbox[2] == 0x0d)) { /* create */
+ if (sc->amr_allow_vol_config == 0) {
+ error = EPERM;
+ break;
+ }
+ logical_drives_changed = 1;
+ }
+
+ if (ali.mbox[0] == AMR_CMD_PASS) {
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ while ((ac = amr_alloccmd(sc)) == NULL)
+ lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ ap = &ac->ac_ccb->ccb_pthru;
+
+ error = copyin((void *)(uintptr_t)mb->mb_physaddr, ap,
+ sizeof(struct amr_passthrough));
+ if (error)
+ break;
+
+ if (ap->ap_data_transfer_length)
+ dp = kmalloc(ap->ap_data_transfer_length, M_AMR,
+ M_WAITOK | M_ZERO);
+
+ if (ali.inlen) {
+ error = copyin((void *)(uintptr_t)ap->ap_data_transfer_address,
+ dp, ap->ap_data_transfer_length);
+ if (error)
+ break;
+ }
+
+ ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB;
+ bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox));
+ ac->ac_mailbox.mb_command = AMR_CMD_PASS;
+ ac->ac_flags = ac_flags;
+
+ ac->ac_data = dp;
+ ac->ac_length = ap->ap_data_transfer_length;
+ temp = (void *)(uintptr_t)ap->ap_data_transfer_address;
+
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ error = amr_wait_command(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (error)
+ break;
+
+ status = ac->ac_status;
+ error = copyout(&status, &((struct amr_passthrough *)(uintptr_t)mb->mb_physaddr)->ap_scsi_status, sizeof(status));
+ if (error)
+ break;
+
+ if (ali.outlen) {
+ error = copyout(dp, temp, ap->ap_data_transfer_length);
+ if (error)
+ break;
+ }
+ error = copyout(ap->ap_request_sense_area, ((struct amr_passthrough *)(uintptr_t)mb->mb_physaddr)->ap_request_sense_area, ap->ap_request_sense_length);
+ if (error)
+ break;
+
+ error = 0;
+ break;
+ } else if (ali.mbox[0] == AMR_CMD_PASS_64) {
+ kprintf("No AMR_CMD_PASS_64\n");
+ error = ENOIOCTL;
+ break;
+ } else if (ali.mbox[0] == AMR_CMD_EXTPASS) {
+ kprintf("No AMR_CMD_EXTPASS\n");
+ error = ENOIOCTL;
+ break;
+ } else {
+ /*
+ * Bug-for-bug compatibility with Linux!
+ * Some apps will send commands with inlen and outlen set to 0,
+ * even though they expect data to be transfered to them from the
+ * card. Linux accidentally allows this by allocating a 4KB
+ * buffer for the transfer anyways, but it then throws it away
+ * without copying it back to the app.
+ */
+ if (!len)
+ len = 4096;
+
+ dp = kmalloc(len, M_AMR, M_WAITOK | M_ZERO);
+
+ if (ali.inlen) {
+ error = copyin((void *)(uintptr_t)mb->mb_physaddr, dp, len);
+ if (error)
+ break;
+ }
+
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ while ((ac = amr_alloccmd(sc)) == NULL)
+ lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz);
+
+ ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT;
+ bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox));
+ bcopy(&ali.mbox[0], &ac->ac_mailbox, sizeof(ali.mbox));
+
+ ac->ac_length = len;
+ ac->ac_data = dp;
+ ac->ac_flags = ac_flags;
+
+ error = amr_wait_command(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (error)
+ break;
+
+ status = ac->ac_status;
+ error = copyout(&status, &((struct amr_mailbox *)&((struct amr_linux_ioctl *)addr)->mbox[0])->mb_status, sizeof(status));
+ if (ali.outlen) {
+ error = copyout(dp, (void *)(uintptr_t)mb->mb_physaddr, len);
+ if (error)
+ break;
+ }
+
+ error = 0;
+ if (logical_drives_changed)
+ amr_rescan_drives(dev);
+ break;
+ }
+ break;
+
+ default:
+ debug(1, "unknown linux ioctl 0x%lx", cmd);
+ kprintf("unknown linux ioctl 0x%lx\n", cmd);
+ error = ENOIOCTL;
+ break;
+ }
+
+ /*
+ * At this point, we know that there is a lock held and that these
+ * objects have been allocated.
+ */
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ if (ac != NULL)
+ amr_releasecmd(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (dp != NULL)
+ kfree(dp, M_AMR);
+ return(error);
+}
+
static int
amr_ioctl(struct dev_ioctl_args *ap)
{
- cdev_t dev = ap->a_head.a_dev;
+ cdev_t dev = ap->a_head.a_dev;
+ caddr_t addr = ap->a_data;
+ u_long cmd = ap->a_cmd;
struct amr_softc *sc = (struct amr_softc *)dev->si_drv1;
- int *arg = (int *)ap->a_data;
- struct amr_user_ioctl *au = (struct amr_user_ioctl *)ap->a_data;
+ union {
+ void *_p;
+ struct amr_user_ioctl *au;
+#ifdef AMR_IO_COMMAND32
+ struct amr_user_ioctl32 *au32;
+#endif
+ int *result;
+ } arg;
struct amr_command *ac;
struct amr_mailbox_ioctl *mbi;
- struct amr_passthrough *apt;
- void *dp;
+ void *dp, *au_buffer;
+ unsigned long au_length;
+ unsigned char *au_cmd;
+ int *au_statusp, au_direction;
int error;
+ struct amr_passthrough *_ap; /* 60 bytes */
+ int logical_drives_changed = 0;
debug_called(1);
+ arg._p = (void *)addr;
+
error = 0;
dp = NULL;
- apt = NULL;
ac = NULL;
- switch(ap->a_cmd) {
+ _ap = NULL;
+
+ switch(cmd) {
case AMR_IO_VERSION:
debug(1, "AMR_IO_VERSION");
- *arg = AMR_IO_VERSION_NUMBER;
+ *arg.result = AMR_IO_VERSION_NUMBER;
+ return(0);
+
+#ifdef AMR_IO_COMMAND32
+ /*
+ * Accept ioctl-s from 32-bit binaries on non-32-bit
+ * platforms, such as AMD. LSI's MEGAMGR utility is
+ * the only example known today... -mi
+ */
+ case AMR_IO_COMMAND32:
+ debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]);
+ au_cmd = arg.au32->au_cmd;
+ au_buffer = (void *)(u_int64_t)arg.au32->au_buffer;
+ au_length = arg.au32->au_length;
+ au_direction = arg.au32->au_direction;
+ au_statusp = &arg.au32->au_status;
break;
+#endif
case AMR_IO_COMMAND:
- debug(1, "AMR_IO_COMMAND 0x%x", au->au_cmd[0]);
- /* handle inbound data buffer */
- if (au->au_length != 0) {
- dp = kmalloc(au->au_length, M_DEVBUF, M_WAITOK);
- if ((error = copyin(au->au_buffer, dp, au->au_length)) != 0)
- break;
- debug(2, "copyin %ld bytes from %p -> %p", au->au_length, au->au_buffer, dp);
+ debug(1, "AMR_IO_COMMAND 0x%x", arg.au->au_cmd[0]);
+ au_cmd = arg.au->au_cmd;
+ au_buffer = (void *)arg.au->au_buffer;
+ au_length = arg.au->au_length;
+ au_direction = arg.au->au_direction;
+ au_statusp = &arg.au->au_status;
+ break;
+
+ case 0xc0046d00:
+ case 0xc06e6d00: /* Linux emulation */
+ {
+ devclass_t devclass;
+ struct amr_linux_ioctl ali;
+ int adapter, error;
+
+ devclass = devclass_find("amr");
+ if (devclass == NULL)
+ return (ENOENT);
+
+ error = copyin(addr, &ali, sizeof(ali));
+ if (error)
+ return (error);
+ if (ali.ui.fcs.opcode == 0x82)
+ adapter = 0;
+ else
+ adapter = (ali.ui.fcs.adapno) ^ 'm' << 8;
+
+ sc = devclass_get_softc(devclass, adapter);
+ if (sc == NULL)
+ return (ENOENT);
+
+ return (amr_linux_ioctl_int(sc->amr_dev_t, cmd, addr, 0, ap->a_sysmsg));
}
+ default:
+ debug(1, "unknown ioctl 0x%lx", cmd);
+ return(ENOIOCTL);
+ }
+
+ if ((au_cmd[0] == FC_DEL_LOGDRV && au_cmd[1] == OP_DEL_LOGDRV) || /* delete */
+ (au_cmd[0] == AMR_CMD_CONFIG && au_cmd[1] == 0x0d)) { /* create */
+ if (sc->amr_allow_vol_config == 0) {
+ error = EPERM;
+ goto out;
+ }
+ logical_drives_changed = 1;
+#ifdef LSI
+ if ((error = amr_prepare_ld_delete(sc)) != 0)
+ return (error);
+#endif
+ }
- if ((ac = amr_alloccmd(sc)) == NULL) {
+ /* handle inbound data buffer */
+ if (au_length != 0 && au_cmd[0] != 0x06) {
+ if ((dp = kmalloc(au_length, M_AMR, M_WAITOK|M_ZERO)) == NULL) {
error = ENOMEM;
- break;
+ goto out;
+ }
+ if ((error = copyin(au_buffer, dp, au_length)) != 0) {
+ kfree(dp, M_AMR);
+ return (error);
}
+ debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp);
+ }
- /* handle SCSI passthrough command */
- if (au->au_cmd[0] == AMR_CMD_PASS) {
- apt = kmalloc(sizeof(*apt), M_DEVBUF, M_WAITOK | M_ZERO);
-
- /* copy cdb */
- apt->ap_cdb_length = au->au_cmd[2];
- bcopy(&au->au_cmd[3], &apt->ap_cdb[0], apt->ap_cdb_length);
-
- /* build passthrough */
- apt->ap_timeout = au->au_cmd[apt->ap_cdb_length + 3] & 0x07;
- apt->ap_ars = (au->au_cmd[apt->ap_cdb_length + 3] & 0x08) ? 1 : 0;
- apt->ap_islogical = (au->au_cmd[apt->ap_cdb_length + 3] & 0x80) ? 1 : 0;
- apt->ap_logical_drive_no = au->au_cmd[apt->ap_cdb_length + 4];
- apt->ap_channel = au->au_cmd[apt->ap_cdb_length + 5];
- apt->ap_scsi_id = au->au_cmd[apt->ap_cdb_length + 6];
- apt->ap_request_sense_length = 14;
- apt->ap_data_transfer_length = au->au_length;
- /* XXX what about the request-sense area? does the caller want it? */
-
- /* build command */
- ac->ac_data = apt;
- ac->ac_length = sizeof(*apt);
- ac->ac_flags |= AMR_CMD_DATAOUT;
- ac->ac_ccb_data = dp;
- ac->ac_ccb_length = au->au_length;
- if (au->au_direction & AMR_IO_READ)
- ac->ac_flags |= AMR_CMD_CCB_DATAIN;
- if (au->au_direction & AMR_IO_WRITE)
- ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
+ /* Allocate this now before the mutex gets held */
- ac->ac_mailbox.mb_command = AMR_CMD_PASS;
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ while ((ac = amr_alloccmd(sc)) == NULL)
+ lksleep(sc, &sc->amr_list_lock, 0, "amrioc", hz);
- } else {
- /* direct command to controller */
- mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
+ /* handle SCSI passthrough command */
+ if (au_cmd[0] == AMR_CMD_PASS) {
+ int len;
- /* copy pertinent mailbox items */
- mbi->mb_command = au->au_cmd[0];
- mbi->mb_channel = au->au_cmd[1];
- mbi->mb_param = au->au_cmd[2];
- mbi->mb_pad[0] = au->au_cmd[3];
- mbi->mb_drive = au->au_cmd[4];
+ _ap = &ac->ac_ccb->ccb_pthru;
+ bzero(_ap, sizeof(struct amr_passthrough));
- /* build the command */
- ac->ac_data = dp;
- ac->ac_length = au->au_length;
- if (au->au_direction & AMR_IO_READ)
- ac->ac_flags |= AMR_CMD_DATAIN;
- if (au->au_direction & AMR_IO_WRITE)
- ac->ac_flags |= AMR_CMD_DATAOUT;
- }
+ /* copy cdb */
+ len = au_cmd[2];
+ _ap->ap_cdb_length = len;
+ bcopy(au_cmd + 3, _ap->ap_cdb, len);
- /* run the command */
- if ((error = amr_wait_command(ac)) != 0)
- break;
+ /* build passthrough */
+ _ap->ap_timeout = au_cmd[len + 3] & 0x07;
+ _ap->ap_ars = (au_cmd[len + 3] & 0x08) ? 1 : 0;
+ _ap->ap_islogical = (au_cmd[len + 3] & 0x80) ? 1 : 0;
+ _ap->ap_logical_drive_no = au_cmd[len + 4];
+ _ap->ap_channel = au_cmd[len + 5];
+ _ap->ap_scsi_id = au_cmd[len + 6];
+ _ap->ap_request_sense_length = 14;
+ _ap->ap_data_transfer_length = au_length;
+ /* XXX what about the request-sense area? does the caller want it? */
- /* copy out data and set status */
- if (au->au_length != 0)
- error = copyout(dp, au->au_buffer, au->au_length);
- debug(2, "copyout %ld bytes from %p -> %p", au->au_length, dp, au->au_buffer);
- if (dp != NULL)
- debug(2, "%16d", (int)dp);
- au->au_status = ac->ac_status;
- break;
+ /* build command */
+ ac->ac_mailbox.mb_command = AMR_CMD_PASS;
+ ac->ac_flags = AMR_CMD_CCB;
- default:
- debug(1, "unknown ioctl 0x%lx", cmd);
- error = ENOIOCTL;
- break;
+ } else {
+ /* direct command to controller */
+ mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
+
+ /* copy pertinent mailbox items */
+ mbi->mb_command = au_cmd[0];
+ mbi->mb_channel = au_cmd[1];
+ mbi->mb_param = au_cmd[2];
+ mbi->mb_pad[0] = au_cmd[3];
+ mbi->mb_drive = au_cmd[4];
+ ac->ac_flags = 0;
}
+ /* build the command */
+ ac->ac_data = dp;
+ ac->ac_length = au_length;
+ ac->ac_flags |= AMR_CMD_DATAIN|AMR_CMD_DATAOUT;
+
+ /* run the command */
+ error = amr_wait_command(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (error)
+ goto out;
+
+ /* copy out data and set status */
+ if (au_length != 0) {
+ error = copyout(dp, au_buffer, au_length);
+ }
+ debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
if (dp != NULL)
- kfree(dp, M_DEVBUF);
- if (apt != NULL)
- kfree(apt, M_DEVBUF);
+ debug(2, "%p status 0x%x", dp, ac->ac_status);
+ *au_statusp = ac->ac_status;
+
+out:
+ /*
+ * At this point, we know that there is a lock held and that these
+ * objects have been allocated.
+ */
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
if (ac != NULL)
amr_releasecmd(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (dp != NULL)
+ kfree(dp, M_AMR);
+
+#ifndef LSI
+ if (logical_drives_changed)
+ amr_rescan_drives(dev);
+#endif
+
return(error);
}
struct amr_prodinfo *ap;
struct amr_enquiry *ae;
int ldrv;
-
- /*
- * If we haven't found the real limit yet, let us have a couple of commands in
- * order to be able to probe.
- */
- if (sc->amr_maxio == 0)
- sc->amr_maxio = 2;
+ int status;
/*
* Greater than 10 byte cdb support
* Try to issue an ENQUIRY3 command
*/
if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
- AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
+ AMR_CONFIG_ENQ3_SOLICITED_FULL, &status)) != NULL) {
/*
* Fetch current state of logical drives.
debug(2, " drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size,
sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties);
}
- kfree(aex, M_DEVBUF);
+ kfree(aex, M_AMR);
/*
* Get product info for channel count.
*/
- if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
+ if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0, &status)) == NULL) {
device_printf(sc->amr_dev, "can't obtain product data from controller\n");
return(1);
}
sc->amr_maxchan = ap->ap_nschan;
sc->amr_maxio = ap->ap_maxio;
sc->amr_type |= AMR_TYPE_40LD;
- kfree(ap, M_DEVBUF);
-
+ kfree(ap, M_AMR);
+
+ ap = amr_enquiry(sc, 0, FC_DEL_LOGDRV, OP_SUP_DEL_LOGDRV, 0, &status);
+ if (ap != NULL)
+ kfree(ap, M_AMR);
+ if (!status) {
+ sc->amr_ld_del_supported = 1;
+ device_printf(sc->amr_dev, "delete logical drives supported by controller\n");
+ }
} else {
/* failed, try the 8LD ENQUIRY commands */
- if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) {
- if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) {
+ if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0, &status)) == NULL) {
+ if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0, &status)) == NULL) {
device_printf(sc->amr_dev, "can't obtain configuration data from controller\n");
return(1);
}
sc->amr_maxdrives = 8;
sc->amr_maxchan = ae->ae_adapter.aa_channels;
sc->amr_maxio = ae->ae_adapter.aa_maxio;
- kfree(ae, M_DEVBUF);
+ kfree(ae, M_AMR);
}
/*
* Run a generic enquiry-style command.
*/
static void *
-amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
+amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual, int *status)
{
struct amr_command *ac;
void *result;
result = NULL;
/* get ourselves a command buffer */
- if ((ac = amr_alloccmd(sc)) == NULL)
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ ac = amr_alloccmd(sc);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (ac == NULL)
goto out;
/* allocate the response structure */
- result = kmalloc(bufsize, M_DEVBUF, M_INTWAIT);
+ if ((result = kmalloc(bufsize, M_AMR, M_ZERO|M_NOWAIT)) == NULL)
+ goto out;
/* set command flags */
- ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
+
+ ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN;
/* point the command at our data */
ac->ac_data = result;
mbox[0] = cmd;
mbox[2] = cmdsub;
mbox[3] = cmdqual;
+ *status = 0;
/* can't assume that interrupts are going to work here, so play it safe */
if (sc->amr_poll_command(ac))
goto out;
error = ac->ac_status;
+ *status = ac->ac_status;
out:
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
if (ac != NULL)
amr_releasecmd(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
if ((error != 0) && (result != NULL)) {
- kfree(result, M_DEVBUF);
+ kfree(result, M_AMR);
result = NULL;
}
return(result);
/* get ourselves a command buffer */
error = 1;
- if ((ac = amr_alloccmd(sc)) == NULL)
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ ac = amr_alloccmd(sc);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (ac == NULL)
goto out;
/* set command flags */
ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
error = ac->ac_status;
out:
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
if (ac != NULL)
amr_releasecmd(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
return(error);
}
/* get ourselves a command buffer */
error = 0;
- if ((ac = amr_alloccmd(sc)) == NULL)
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ ac = amr_alloccmd(sc);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (ac == NULL)
goto out;
/* set command flags */
ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
}
out:
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
if (ac != NULL)
amr_releasecmd(ac);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
return(error);
}
/* spin until something prevents us from doing any work */
for (;;) {
+ /* Don't bother to queue commands no bounce buffers are available. */
+ if (sc->amr_state & AMR_STATE_QUEUE_FRZN)
+ break;
+
/* try to get a ready command */
ac = amr_dequeue_ready(sc);
(void)amr_bio_command(sc, &ac);
/* if that failed, build a command from a ccb */
- if (ac == NULL)
- (void)amr_cam_command(sc, &ac);
+ if ((ac == NULL) && (sc->amr_cam_command != NULL))
+ sc->amr_cam_command(sc, &ac);
/* if we don't have anything to do, give up */
if (ac == NULL)
static void
amr_completeio(struct amr_command *ac)
{
- struct amr_softc *sc = ac->ac_sc;
-
+ struct amr_softc *sc = ac->ac_sc;
+ static struct timeval lastfail;
+ static int curfail;
+ struct buf *bp = ac->ac_bio->bio_buf;
+
if (ac->ac_status != AMR_STATUS_SUCCESS) { /* could be more verbose here? */
- ac->ac_bio->bio_buf->b_error = EIO;
- ac->ac_bio->bio_buf->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
- device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status);
+ if (ppsratecheck(&lastfail, &curfail, 1))
+ device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status);
/* amr_printcommand(ac);*/
}
amrd_intr(ac->ac_bio);
+ lockmgr(&ac->ac_sc->amr_list_lock, LK_EXCLUSIVE);
amr_releasecmd(ac);
+ lockmgr(&ac->ac_sc->amr_list_lock, LK_RELEASE);
}
/********************************************************************************
struct amr_command *ac;
struct amrd_softc *amrd;
struct bio *bio;
+ struct buf *bp;
int error;
int blkcount;
int driveno;
int cmd;
- u_int64_t lba;
ac = NULL;
error = 0;
+ /* get a command */
+ if ((ac = amr_alloccmd(sc)) == NULL)
+ return (ENOMEM);
+
/* get a bio to work on */
- if ((bio = amr_dequeue_bio(sc)) == NULL)
- goto out;
+ if ((bio = amr_dequeue_bio(sc)) == NULL) {
+ amr_releasecmd(ac);
+ return (0);
+ }
- /* get a command */
- if ((ac = amr_alloccmd(sc)) == NULL) {
- error = ENOMEM;
- goto out;
- }
-
/* connect the bio to the command */
+ bp = bio->bio_buf;
ac->ac_complete = amr_completeio;
ac->ac_bio = bio;
- ac->ac_data = bio->bio_buf->b_data;
- ac->ac_length = bio->bio_buf->b_bcount;
-
- switch (bio->bio_buf->b_cmd) {
+ ac->ac_data = bp->b_data;
+ ac->ac_length = bp->b_bcount;
+ cmd = 0;
+ switch (bp->b_cmd) {
case BUF_CMD_READ:
ac->ac_flags |= AMR_CMD_DATAIN;
- cmd = AMR_CMD_LREAD;
+ if (AMR_IS_SG64(sc)) {
+ cmd = AMR_CMD_LREAD64;
+ ac->ac_flags |= AMR_CMD_SG64;
+ } else
+ cmd = AMR_CMD_LREAD;
break;
case BUF_CMD_WRITE:
ac->ac_flags |= AMR_CMD_DATAOUT;
- cmd = AMR_CMD_LWRITE;
+ if (AMR_IS_SG64(sc)) {
+ cmd = AMR_CMD_LWRITE64;
+ ac->ac_flags |= AMR_CMD_SG64;
+ } else
+ cmd = AMR_CMD_LWRITE;
break;
case BUF_CMD_FLUSH:
ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT;
cmd = AMR_CMD_FLUSH;
break;
default:
- cmd = 0;
- break;
+ panic("Invalid bio command");
}
amrd = (struct amrd_softc *)bio->bio_driver_info;
driveno = amrd->amrd_drive - sc->amr_drive;
- blkcount = (bio->bio_buf->b_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE;
-
- lba = bio->bio_offset / AMR_BLKSIZE;
- KKASSERT(lba < 0x100000000ULL);
+ blkcount = (bp->b_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE;
ac->ac_mailbox.mb_command = cmd;
- ac->ac_mailbox.mb_blkcount = blkcount;
- ac->ac_mailbox.mb_lba = lba;
+ if (bp->b_cmd & (BUF_CMD_READ|BUF_CMD_WRITE)) {
+ ac->ac_mailbox.mb_blkcount = blkcount;
+ ac->ac_mailbox.mb_lba = bio->bio_offset / AMR_BLKSIZE;
+ if (((bio->bio_offset / AMR_BLKSIZE) + blkcount) > sc->amr_drive[driveno].al_size) {
+ device_printf(sc->amr_dev,
+ "I/O beyond end of unit (%lld,%d > %lu)\n",
+ (long long)(bio->bio_offset / AMR_BLKSIZE), blkcount,
+ (u_long)sc->amr_drive[driveno].al_size);
+ }
+ }
ac->ac_mailbox.mb_drive = driveno;
+ if (sc->amr_state & AMR_STATE_REMAP_LD)
+ ac->ac_mailbox.mb_drive |= 0x80;
+
/* we fill in the s/g related data when the command is mapped */
- if ((lba + blkcount) > sc->amr_drive[driveno].al_size)
- device_printf(sc->amr_dev, "I/O beyond end of unit (%ju,%d > %lu)\n",
- (uintmax_t)lba, blkcount,
- (u_long)sc->amr_drive[driveno].al_size);
-out:
- if (error != 0) {
- if (ac != NULL)
- amr_releasecmd(ac);
- if (bio != NULL) /* this breaks ordering... */
- amr_enqueue_bio(sc, bio);
- }
*acp = ac;
return(error);
}
static int
amr_wait_command(struct amr_command *ac)
{
- int error, count;
-
+ int error = 0;
+ struct amr_softc *sc = ac->ac_sc;
+
debug_called(1);
ac->ac_complete = NULL;
ac->ac_flags |= AMR_CMD_SLEEP;
- if ((error = amr_start(ac)) != 0)
+ if ((error = amr_start(ac)) != 0) {
return(error);
+ }
- count = 0;
- /* XXX better timeout? */
- while ((ac->ac_flags & AMR_CMD_BUSY) && (count < 30)) {
- tsleep(ac, PCATCH, "amrwcmd", hz);
+ while ((ac->ac_flags & AMR_CMD_BUSY) && (error != EWOULDBLOCK)) {
+ error = lksleep(ac,&sc->amr_list_lock, 0, "amrwcmd", 0);
}
- return(0);
+
+ return(error);
}
/********************************************************************************
return(error);
}
+static void
+amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
+{
+ struct amr_command *ac = arg;
+ struct amr_softc *sc = ac->ac_sc;
+ int mb_channel;
+
+ if (err) {
+ device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__);
+ ac->ac_status = AMR_STATUS_ABORTED;
+ return;
+ }
+
+ amr_setup_sg(arg, segs, nsegs, err);
+
+ /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
+ mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel;
+ if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG &&
+ ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) ||
+ (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)))
+ ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments;
+
+ ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments;
+ ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr;
+ if (AC_IS_SG64(ac)) {
+ ac->ac_sg64_hi = 0;
+ ac->ac_sg64_lo = ac->ac_sgbusaddr;
+ }
+
+ sc->amr_poll_command1(sc, ac);
+}
+
/********************************************************************************
* Take a command, submit it to the controller and busy-wait for it to return.
* Returns nonzero on error. Can be safely called with interrupts enabled.
amr_quartz_poll_command(struct amr_command *ac)
{
struct amr_softc *sc = ac->ac_sc;
- int error,count;
+ int error;
debug_called(2);
+ error = 0;
+
+ if (AC_IS_SG64(ac)) {
+ ac->ac_tag = sc->amr_buffer64_dmat;
+ ac->ac_datamap = ac->ac_dma64map;
+ } else {
+ ac->ac_tag = sc->amr_buffer_dmat;
+ ac->ac_datamap = ac->ac_dmamap;
+ }
+
/* now we have a slot, we can map the command (unmapped in amr_complete) */
- amr_mapcmd(ac);
+ if (ac->ac_data != NULL && ac->ac_length != 0) {
+ if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data,
+ ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) {
+ error = 1;
+ }
+ } else {
+ error = amr_quartz_poll_command1(sc, ac);
+ }
- crit_enter();
+ return (error);
+}
- if (sc->amr_state & AMR_STATE_INTEN) {
- count=0;
- while (sc->amr_busyslots) {
- tsleep(sc, PCATCH, "amrpoll", hz);
- if(count++>10) {
- break;
- }
+static int
+amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac)
+{
+ int count, error;
+
+ lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE);
+ if ((sc->amr_state & AMR_STATE_INTEN) == 0) {
+ count=0;
+ while (sc->amr_busyslots) {
+ lksleep(sc, &sc->amr_hw_lock, PCATCH, "amrpoll", hz);
+ if(count++>10) {
+ break;
}
-
- if(sc->amr_busyslots) {
- device_printf(sc->amr_dev, "adapter is busy\n");
- crit_exit();
- amr_unmapcmd(ac);
- ac->ac_status=0;
- return(1);
+ }
+
+ if(sc->amr_busyslots) {
+ device_printf(sc->amr_dev, "adapter is busy\n");
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
+ if (ac->ac_data != NULL) {
+ bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
}
+ ac->ac_status=0;
+ return(1);
+ }
}
bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
- while(sc->amr_mailbox->mb_nstatus == 0xFF);
- while(sc->amr_mailbox->mb_status == 0xFF);
+ while(sc->amr_mailbox->mb_nstatus == 0xFF)
+ DELAY(1);
+ while(sc->amr_mailbox->mb_status == 0xFF)
+ DELAY(1);
ac->ac_status=sc->amr_mailbox->mb_status;
error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0;
- while(sc->amr_mailbox->mb_poll != 0x77);
+ while(sc->amr_mailbox->mb_poll != 0x77)
+ DELAY(1);
sc->amr_mailbox->mb_poll = 0;
sc->amr_mailbox->mb_ack = 0x77;
/* acknowledge that we have the commands */
AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
- while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK);
-
- crit_exit();
+ while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
+ DELAY(1);
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
/* unmap the command's data buffer */
- amr_unmapcmd(ac);
+ if (ac->ac_flags & AMR_CMD_DATAIN) {
+ bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTREAD);
+ }
+ if (ac->ac_flags & AMR_CMD_DATAOUT) {
+ bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTWRITE);
+ }
+ bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
return(error);
}
-/********************************************************************************
- * Get a free command slot for a command if it doesn't already have one.
- *
- * May be safely called multiple times for a given command.
- */
-static int
-amr_getslot(struct amr_command *ac)
+static __inline int
+amr_freeslot(struct amr_command *ac)
{
- struct amr_softc *sc = ac->ac_sc;
- int slot, limit, error;
+ struct amr_softc *sc = ac->ac_sc;
+ int slot;
debug_called(3);
- /* if the command already has a slot, don't try to give it another one */
- if (ac->ac_slot != 0)
- return(0);
+ slot = ac->ac_slot;
+ if (sc->amr_busycmd[slot] == NULL)
+ panic("amr: slot %d not busy?\n", slot);
- /* enforce slot usage limit */
- limit = (ac->ac_flags & AMR_CMD_PRIORITY) ? sc->amr_maxio : sc->amr_maxio - 4;
- if (sc->amr_busyslots > limit)
- return(EBUSY);
-
- /*
- * Allocate a slot. XXX linear scan is slow
- */
- error = EBUSY;
- crit_enter();
- for (slot = 0; slot < sc->amr_maxio; slot++) {
- if (sc->amr_busycmd[slot] == NULL) {
- sc->amr_busycmd[slot] = ac;
- sc->amr_busyslots++;
- ac->ac_slot = slot;
- error = 0;
- break;
- }
- }
- crit_exit();
+ sc->amr_busycmd[slot] = NULL;
+ atomic_subtract_int(&sc->amr_busyslots, 1);
- return(error);
+ return (0);
}
/********************************************************************************
* These functions may be safely called multiple times on a given command.
*/
static void
-amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
+amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
{
struct amr_command *ac = (struct amr_command *)arg;
- struct amr_softc *sc = ac->ac_sc;
struct amr_sgentry *sg;
- int i;
- u_int8_t *sgc;
+ struct amr_sg64entry *sg64;
+ int flags, i;
debug_called(3);
/* get base address of s/g table */
- sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
+ sg = ac->ac_sg.sg32;
+ sg64 = ac->ac_sg.sg64;
+
+ if (AC_IS_SG64(ac)) {
+ ac->ac_nsegments = nsegments;
+ ac->ac_mb_physaddr = 0xffffffff;
+ for (i = 0; i < nsegments; i++, sg64++) {
+ sg64->sg_addr = segs[i].ds_addr;
+ sg64->sg_count = segs[i].ds_len;
+ }
+ } else {
+ /* decide whether we need to populate the s/g table */
+ if (nsegments < 2) {
+ ac->ac_nsegments = 0;
+ ac->ac_mb_physaddr = segs[0].ds_addr;
+ } else {
+ ac->ac_nsegments = nsegments;
+ ac->ac_mb_physaddr = ac->ac_sgbusaddr;
+ for (i = 0; i < nsegments; i++, sg++) {
+ sg->sg_addr = segs[i].ds_addr;
+ sg->sg_count = segs[i].ds_len;
+ }
+ }
+ }
- /* save data physical address */
- ac->ac_dataphys = segs[0].ds_addr;
+ flags = 0;
+ if (ac->ac_flags & AMR_CMD_DATAIN)
+ flags |= BUS_DMASYNC_PREREAD;
+ if (ac->ac_flags & AMR_CMD_DATAOUT)
+ flags |= BUS_DMASYNC_PREWRITE;
+ bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flags);
+ ac->ac_flags |= AMR_CMD_MAPPED;
+}
- /* for AMR_CMD_CONFIG the s/g count goes elsewhere */
- if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) {
- sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
- } else {
- sgc = &ac->ac_mailbox.mb_nsgelem;
+static void
+amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
+{
+ struct amr_command *ac = arg;
+ struct amr_softc *sc = ac->ac_sc;
+ int mb_channel;
+
+ if (err) {
+ device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__);
+ amr_abort_load(ac);
+ return;
}
- /* decide whether we need to populate the s/g table */
- if (nsegments < 2) {
- *sgc = 0;
- ac->ac_mailbox.mb_nsgelem = 0;
- ac->ac_mailbox.mb_physaddr = ac->ac_dataphys;
- } else {
- ac->ac_mailbox.mb_nsgelem = nsegments;
- *sgc = nsegments;
- ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
- for (i = 0; i < nsegments; i++, sg++) {
- sg->sg_addr = segs[i].ds_addr;
- sg->sg_count = segs[i].ds_len;
- }
+ amr_setup_sg(arg, segs, nsegs, err);
+
+ /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
+ mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel;
+ if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG &&
+ ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) ||
+ (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)))
+ ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments;
+
+ ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments;
+ ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr;
+ if (AC_IS_SG64(ac)) {
+ ac->ac_sg64_hi = 0;
+ ac->ac_sg64_lo = ac->ac_sgbusaddr;
+ }
+
+ if (sc->amr_submit_command(ac) == EBUSY) {
+ amr_freeslot(ac);
+ amr_requeue_ready(ac);
}
}
static void
-amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
+amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
{
- struct amr_command *ac = (struct amr_command *)arg;
- struct amr_softc *sc = ac->ac_sc;
- struct amr_sgentry *sg;
- struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data;
- struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data;
- int i;
+ struct amr_command *ac = arg;
+ struct amr_softc *sc = ac->ac_sc;
+ struct amr_passthrough *ap = &ac->ac_ccb->ccb_pthru;
+ struct amr_ext_passthrough *aep = &ac->ac_ccb->ccb_epthru;
+
+ if (err) {
+ device_printf(sc->amr_dev, "error %d in %s", err, __FUNCTION__);
+ amr_abort_load(ac);
+ return;
+ }
- /* get base address of s/g table */
- sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
+ /* Set up the mailbox portion of the command to point at the ccb */
+ ac->ac_mailbox.mb_nsgelem = 0;
+ ac->ac_mailbox.mb_physaddr = ac->ac_ccb_busaddr;
- /* decide whether we need to populate the s/g table */
- if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
- if (nsegments < 2) {
- aep->ap_no_sg_elements = 0;
- aep->ap_data_transfer_address = segs[0].ds_addr;
- } else {
- /* save s/g table information in passthrough */
- aep->ap_no_sg_elements = nsegments;
- aep->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
- /* populate s/g table (overwrites previous call which mapped the passthrough) */
- for (i = 0; i < nsegments; i++, sg++) {
- sg->sg_addr = segs[i].ds_addr;
- sg->sg_count = segs[i].ds_len;
- debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
- }
- }
- debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot,
- aep->ap_no_sg_elements, aep->ap_data_transfer_address, ac->ac_dataphys);
- } else {
- if (nsegments < 2) {
- ap->ap_no_sg_elements = 0;
- ap->ap_data_transfer_address = segs[0].ds_addr;
- } else {
- /* save s/g table information in passthrough */
- ap->ap_no_sg_elements = nsegments;
- ap->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
- /* populate s/g table (overwrites previous call which mapped the passthrough) */
- for (i = 0; i < nsegments; i++, sg++) {
- sg->sg_addr = segs[i].ds_addr;
- sg->sg_count = segs[i].ds_len;
- debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
- }
- }
- debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot,
- ap->ap_no_sg_elements, ap->ap_data_transfer_address, ac->ac_dataphys);
+ amr_setup_sg(arg, segs, nsegs, err);
+
+ switch (ac->ac_mailbox.mb_command) {
+ case AMR_CMD_EXTPASS:
+ aep->ap_no_sg_elements = ac->ac_nsegments;
+ aep->ap_data_transfer_address = ac->ac_mb_physaddr;
+ break;
+ case AMR_CMD_PASS:
+ ap->ap_no_sg_elements = ac->ac_nsegments;
+ ap->ap_data_transfer_address = ac->ac_mb_physaddr;
+ break;
+ default:
+ panic("Unknown ccb command");
+ }
+
+ if (sc->amr_submit_command(ac) == EBUSY) {
+ amr_freeslot(ac);
+ amr_requeue_ready(ac);
}
}
-static void
+static int
amr_mapcmd(struct amr_command *ac)
{
+ bus_dmamap_callback_t *cb;
struct amr_softc *sc = ac->ac_sc;
debug_called(3);
- /* if the command involves data at all, and hasn't been mapped */
- if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
+ if (AC_IS_SG64(ac)) {
+ ac->ac_tag = sc->amr_buffer64_dmat;
+ ac->ac_datamap = ac->ac_dma64map;
+ } else {
+ ac->ac_tag = sc->amr_buffer_dmat;
+ ac->ac_datamap = ac->ac_dmamap;
+ }
- if (ac->ac_data != NULL) {
- /* map the data buffers into bus space and build the s/g list */
- bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, ac->ac_length,
- amr_setup_dmamap, ac, 0);
- if (ac->ac_flags & AMR_CMD_DATAIN)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREREAD);
- if (ac->ac_flags & AMR_CMD_DATAOUT)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREWRITE);
- }
+ if (ac->ac_flags & AMR_CMD_CCB)
+ cb = amr_setup_ccb;
+ else
+ cb = amr_setup_data;
- if (ac->ac_ccb_data != NULL) {
- bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, ac->ac_ccb_data, ac->ac_ccb_length,
- amr_setup_ccbmap, ac, 0);
- if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREREAD);
- if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_PREWRITE);
+ /* if the command involves data at all, and hasn't been mapped */
+ if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) {
+ /* map the data buffers into bus space and build the s/g list */
+ if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data,
+ ac->ac_length, cb, ac, 0) == EINPROGRESS) {
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
}
- ac->ac_flags |= AMR_CMD_MAPPED;
- }
+ } else {
+ if (sc->amr_submit_command(ac) == EBUSY) {
+ amr_freeslot(ac);
+ amr_requeue_ready(ac);
+ }
+ }
+
+ return (0);
}
static void
amr_unmapcmd(struct amr_command *ac)
{
- struct amr_softc *sc = ac->ac_sc;
+ int flag;
debug_called(3);
if (ac->ac_flags & AMR_CMD_MAPPED) {
if (ac->ac_data != NULL) {
+
+ flag = 0;
if (ac->ac_flags & AMR_CMD_DATAIN)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD);
+ flag |= BUS_DMASYNC_POSTREAD;
if (ac->ac_flags & AMR_CMD_DATAOUT)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
- }
+ flag |= BUS_DMASYNC_POSTWRITE;
- if (ac->ac_ccb_data != NULL) {
- if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTREAD);
- if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
- bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap);
+ bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flag);
+ bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
}
+
ac->ac_flags &= ~AMR_CMD_MAPPED;
}
}
+static void
+amr_abort_load(struct amr_command *ac)
+{
+ ac_qhead_t head;
+ struct amr_softc *sc = ac->ac_sc;
+
+ KKASSERT(lockstatus(&sc->amr_list_lock, curthread) != 0);
+
+ ac->ac_status = AMR_STATUS_ABORTED;
+ amr_init_qhead(&head);
+ amr_enqueue_completed(ac, &head);
+
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ amr_complete(sc, &head);
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+}
+
/********************************************************************************
* Take a command and give it to the controller, returns 0 if successful, or
* EBUSY if the command should be retried later.
static int
amr_start(struct amr_command *ac)
{
- struct amr_softc *sc = ac->ac_sc;
- int done, i;
+ struct amr_softc *sc;
+ int error = 0;
+ int slot;
debug_called(3);
/* mark command as busy so that polling consumer can tell */
+ sc = ac->ac_sc;
ac->ac_flags |= AMR_CMD_BUSY;
/* get a command slot (freed in amr_done) */
- if (amr_getslot(ac))
- return(EBUSY);
-
- /* now we have a slot, we can map the command (unmapped in amr_complete) */
- amr_mapcmd(ac);
-
- /* mark the new mailbox we are going to copy in as busy */
- ac->ac_mailbox.mb_busy = 1;
-
- /* clear the poll/ack fields in the mailbox */
- sc->amr_mailbox->mb_poll = 0;
- sc->amr_mailbox->mb_ack = 0;
-
- /*
- * Save the slot number so that we can locate this command when complete.
- * Note that ident = 0 seems to be special, so we don't use it.
- */
- ac->ac_mailbox.mb_ident = ac->ac_slot + 1;
-
- /*
- * Spin waiting for the mailbox, give up after ~1 second. We expect the
- * controller to be able to handle our I/O.
- *
- * XXX perhaps we should wait for less time, and count on the deferred command
- * handling to deal with retries?
- */
- debug(4, "wait for mailbox");
- for (i = 10000, done = 0; (i > 0) && !done; i--) {
- crit_enter();
-
- /* is the mailbox free? */
- if (sc->amr_mailbox->mb_busy == 0) {
- debug(4, "got mailbox");
- sc->amr_mailbox64->mb64_segment = 0;
- bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE);
- done = 1;
-
- /* not free, spin waiting */
- } else {
- debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy);
- /* this is somewhat ugly */
- DELAY(100);
- }
- crit_exit();
+ slot = ac->ac_slot;
+ if (sc->amr_busycmd[slot] != NULL)
+ panic("amr: slot %d busy?\n", slot);
+ sc->amr_busycmd[slot] = ac;
+ atomic_add_int(&sc->amr_busyslots, 1);
+
+ /* Now we have a slot, we can map the command (unmapped in amr_complete). */
+ if ((error = amr_mapcmd(ac)) == ENOMEM) {
+ /*
+ * Memroy resources are short, so free the slot and let this be tried
+ * later.
+ */
+ amr_freeslot(ac);
}
- /*
- * Now give the command to the controller
- */
- if (done) {
- if (sc->amr_submit_command(sc)) {
- /* the controller wasn't ready to take the command, forget that we tried to post it */
- sc->amr_mailbox->mb_busy = 0;
- return(EBUSY);
- }
- debug(3, "posted command");
- return(0);
- }
-
- /*
- * The controller wouldn't take the command. Return the command as busy
- * so that it is retried later.
- */
- return(EBUSY);
+ return (error);
}
/********************************************************************************
*
* Returns nonzero if any commands on the work queue were marked as completed.
*/
+
int
amr_done(struct amr_softc *sc)
{
+ ac_qhead_t head;
struct amr_command *ac;
struct amr_mailbox mbox;
int i, idx, result;
/* See if there's anything for us to do */
result = 0;
+ amr_init_qhead(&head);
/* loop collecting completed commands */
for (;;) {
if (ac != NULL) {
/* pull the command from the busy index */
- sc->amr_busycmd[idx] = NULL;
- sc->amr_busyslots--;
+ amr_freeslot(ac);
/* save status for later use */
ac->ac_status = mbox.mb_status;
- amr_enqueue_completed(ac);
+ amr_enqueue_completed(ac, &head);
debug(3, "completed command with status %x", mbox.mb_status);
} else {
device_printf(sc->amr_dev, "bad slot %d completed\n", idx);
}
}
- } else {
+ } else
break; /* no work */
- }
}
-
- /* if we've completed any commands, try posting some more */
- if (result)
- amr_startio(sc);
-
+
/* handle completion and timeouts */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
- if (sc->amr_state & AMR_STATE_INTEN)
- taskqueue_enqueue(taskqueue_swi, &sc->amr_task_complete);
- else
-#endif
- amr_complete(sc, 0);
-
+ amr_complete(sc, &head);
+
return(result);
}
/********************************************************************************
* Do completion processing on done commands on (sc)
*/
+
static void
-amr_complete(void *context, int pending)
+amr_complete(void *context, ac_qhead_t *head)
{
struct amr_softc *sc = (struct amr_softc *)context;
struct amr_command *ac;
/* pull completed commands off the queue */
for (;;) {
- ac = amr_dequeue_completed(sc);
+ ac = amr_dequeue_completed(sc, head);
if (ac == NULL)
break;
/* unmap the command's data buffer */
amr_unmapcmd(ac);
- /* unbusy the command */
- ac->ac_flags &= ~AMR_CMD_BUSY;
-
/*
* Is there a completion handler?
*/
if (ac->ac_complete != NULL) {
+ /* unbusy the command */
+ ac->ac_flags &= ~AMR_CMD_BUSY;
ac->ac_complete(ac);
/*
* Is someone sleeping on this one?
*/
- } else if (ac->ac_flags & AMR_CMD_SLEEP) {
- wakeup(ac);
+ } else {
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ ac->ac_flags &= ~AMR_CMD_BUSY;
+ if (ac->ac_flags & AMR_CMD_SLEEP) {
+ /* unbusy the command */
+ wakeup(ac);
+ }
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
}
if(!sc->amr_busyslots) {
wakeup(sc);
}
}
+
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ sc->amr_state &= ~AMR_STATE_QUEUE_FRZN;
+ amr_startio(sc);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
}
/********************************************************************************
ac = amr_dequeue_free(sc);
if (ac == NULL) {
- amr_alloccmd_cluster(sc);
- ac = amr_dequeue_free(sc);
- }
- if (ac == NULL)
+ sc->amr_state |= AMR_STATE_QUEUE_FRZN;
return(NULL);
+ }
/* clear out significant fields */
- ac->ac_slot = 0;
ac->ac_status = 0;
bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox));
ac->ac_flags = 0;
ac->ac_bio = NULL;
ac->ac_data = NULL;
- ac->ac_ccb_data = NULL;
ac->ac_complete = NULL;
+ ac->ac_retries = 0;
+ ac->ac_tag = NULL;
+ ac->ac_datamap = NULL;
return(ac);
}
{
struct amr_command_cluster *acc;
struct amr_command *ac;
- int i;
+ int i, nextslot;
- acc = kmalloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_INTWAIT);
- crit_enter();
- TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link);
- crit_exit();
- for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
- ac = &acc->acc_command[i];
- bzero(ac, sizeof(*ac));
- ac->ac_sc = sc;
- if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) &&
- !bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap))
+ /*
+ * If we haven't found the real limit yet, let us have a couple of
+ * commands in order to be able to probe.
+ */
+ if (sc->amr_maxio == 0)
+ sc->amr_maxio = 2;
+
+ if (sc->amr_nextslot > sc->amr_maxio)
+ return;
+ acc = kmalloc(AMR_CMD_CLUSTERSIZE, M_AMR, M_NOWAIT | M_ZERO);
+ if (acc != NULL) {
+ nextslot = sc->amr_nextslot;
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
+ ac = &acc->acc_command[i];
+ ac->ac_sc = sc;
+ ac->ac_slot = nextslot;
+
+ /*
+ * The SG table for each slot is a fixed size and is assumed to
+ * to hold 64-bit s/g objects when the driver is configured to do
+ * 64-bit DMA. 32-bit DMA commands still use the same table, but
+ * cast down to 32-bit objects.
+ */
+ if (AMR_IS_SG64(sc)) {
+ ac->ac_sgbusaddr = sc->amr_sgbusaddr +
+ (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sg64entry));
+ ac->ac_sg.sg64 = sc->amr_sg64table + (ac->ac_slot * AMR_NSEG);
+ } else {
+ ac->ac_sgbusaddr = sc->amr_sgbusaddr +
+ (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry));
+ ac->ac_sg.sg32 = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
+ }
+
+ ac->ac_ccb = sc->amr_ccb + ac->ac_slot;
+ ac->ac_ccb_busaddr = sc->amr_ccb_busaddr +
+ (ac->ac_slot * sizeof(union amr_ccb));
+
+ if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap))
+ break;
+ if (AMR_IS_SG64(sc) &&
+ (bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map)))
+ break;
amr_releasecmd(ac);
+ if (++nextslot > sc->amr_maxio)
+ break;
+ }
+ sc->amr_nextslot = nextslot;
}
}
struct amr_softc *sc = acc->acc_command[0].ac_sc;
int i;
- for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++)
+ for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
+ if (acc->acc_command[i].ac_sc == NULL)
+ break;
bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap);
- kfree(acc, M_DEVBUF);
+ if (AMR_IS_SG64(sc))
+ bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_dma64map);
+ }
+ kfree(acc, M_AMR);
}
/********************************************************************************
* Tell the controller that the mailbox contains a valid command
*/
static int
-amr_quartz_submit_command(struct amr_softc *sc)
+amr_quartz_submit_command(struct amr_command *ac)
{
- debug_called(3);
+ struct amr_softc *sc = ac->ac_sc;
+ static struct timeval lastfail;
+ static int curfail;
+ int i = 0;
+
+ lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE);
+ while (sc->amr_mailbox->mb_busy && (i++ < 10)) {
+ DELAY(1);
+ /* This is a no-op read that flushes pending mailbox updates */
+ AMR_QGET_ODB(sc);
+ }
+ if (sc->amr_mailbox->mb_busy) {
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
+ if (ac->ac_retries++ > 1000) {
+ if (ppsratecheck(&lastfail, &curfail, 1))
+ device_printf(sc->amr_dev, "Too many retries on command %p. "
+ "Controller is likely dead\n", ac);
+ ac->ac_retries = 0;
+ }
+ return (EBUSY);
+ }
+
+ /*
+ * Save the slot number so that we can locate this command when complete.
+ * Note that ident = 0 seems to be special, so we don't use it.
+ */
+ ac->ac_mailbox.mb_ident = ac->ac_slot + 1; /* will be coppied into mbox */
+ bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, 14);
+ sc->amr_mailbox->mb_busy = 1;
+ sc->amr_mailbox->mb_poll = 0;
+ sc->amr_mailbox->mb_ack = 0;
+ sc->amr_mailbox64->sg64_hi = ac->ac_sg64_hi;
+ sc->amr_mailbox64->sg64_lo = ac->ac_sg64_lo;
- if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT)
- return(EBUSY);
AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT);
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
return(0);
}
static int
-amr_std_submit_command(struct amr_softc *sc)
+amr_std_submit_command(struct amr_command *ac)
{
- debug_called(3);
+ struct amr_softc *sc = ac->ac_sc;
+ static struct timeval lastfail;
+ static int curfail;
+
+ lockmgr(&sc->amr_hw_lock, LK_EXCLUSIVE);
+ if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG) {
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
+ if (ac->ac_retries++ > 1000) {
+ if (ppsratecheck(&lastfail, &curfail, 1))
+ device_printf(sc->amr_dev, "Too many retries on command %p. "
+ "Controller is likely dead\n", ac);
+ ac->ac_retries = 0;
+ }
+ return (EBUSY);
+ }
+
+ /*
+ * Save the slot number so that we can locate this command when complete.
+ * Note that ident = 0 seems to be special, so we don't use it.
+ */
+ ac->ac_mailbox.mb_ident = ac->ac_slot + 1; /* will be coppied into mbox */
+ bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, 14);
+ sc->amr_mailbox->mb_busy = 1;
+ sc->amr_mailbox->mb_poll = 0;
+ sc->amr_mailbox->mb_ack = 0;
- if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG)
- return(EBUSY);
AMR_SPOST_COMMAND(sc);
+ lockmgr(&sc->amr_hw_lock, LK_RELEASE);
return(0);
}
static int
amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave)
{
- int worked;
+ int worked, i;
u_int32_t outd;
+ u_int8_t nstatus;
+ u_int8_t completed[46];
debug_called(3);
worked = 0;
- crit_enter();
/* work waiting for us? */
if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) {
- /* save mailbox, which contains a list of completed commands */
- bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave));
-
/* acknowledge interrupt */
AMR_QPUT_ODB(sc, AMR_QODB_READY);
+ while ((nstatus = sc->amr_mailbox->mb_nstatus) == 0xff)
+ DELAY(1);
+ sc->amr_mailbox->mb_nstatus = 0xff;
+
+ /* wait until fw wrote out all completions */
+ for (i = 0; i < nstatus; i++) {
+ while ((completed[i] = sc->amr_mailbox->mb_completed[i]) == 0xff)
+ DELAY(1);
+ sc->amr_mailbox->mb_completed[i] = 0xff;
+ }
+
+ /* Save information for later processing */
+ mbsave->mb_nstatus = nstatus;
+ mbsave->mb_status = sc->amr_mailbox->mb_status;
+ sc->amr_mailbox->mb_status = 0xff;
+
+ for (i = 0; i < nstatus; i++)
+ mbsave->mb_completed[i] = completed[i];
+
/* acknowledge that we have the commands */
- AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK);
+ AMR_QPUT_IDB(sc, AMR_QIDB_ACK);
+#if 0
#ifndef AMR_QUARTZ_GOFASTER
/*
* This waits for the controller to notice that we've taken the
while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK)
; /* XXX aiee! what if it dies? */
#endif
+#endif
worked = 1; /* got some work */
}
- crit_exit();
return(worked);
}
debug_called(3);
worked = 0;
- crit_enter();
/* check for valid interrupt status */
istat = AMR_SGET_ISTAT(sc);
worked = 1;
}
- crit_exit();
return(worked);
}
struct amr_prodinfo *ap;
struct amr_enquiry *ae;
char *prod;
+ int status;
/*
* Try to get 40LD product info, which tells us what the card is labelled as.
*/
- if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) {
+ if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0, &status)) != NULL) {
device_printf(sc->amr_dev, "<LSILogic %.80s> Firmware %.16s, BIOS %.16s, %dMB RAM\n",
ap->ap_product, ap->ap_firmware, ap->ap_bios,
ap->ap_memsize);
- kfree(ap, M_DEVBUF);
+ kfree(ap, M_AMR);
return;
}
/*
* Try 8LD extended ENQUIRY to get controller signature, and use lookup table.
*/
- if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) {
+ if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0, &status)) != NULL) {
prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature);
- } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) {
+ } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0, &status)) != NULL) {
/*
* Try to work it out based on the PCI signatures.
prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios,
ae->ae_adapter.aa_memorysize);
}
- kfree(ae, M_DEVBUF);
+ kfree(ae, M_AMR);
}
int
-amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int blks)
+amr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks)
{
-
struct amr_command *ac;
- int error = 1;
+ int error = EIO;
debug_called(1);
- sc->amr_state &= ~AMR_STATE_INTEN;
+ sc->amr_state |= AMR_STATE_INTEN;
/* get ourselves a command buffer */
if ((ac = amr_alloccmd(sc)) == NULL)
ac->ac_mailbox.mb_blkcount = blks;
ac->ac_mailbox.mb_lba = lba;
ac->ac_mailbox.mb_drive = unit;
-
+
/* can't assume that interrupts are going to work here, so play it safe */
if (sc->amr_poll_command(ac))
goto out;
if (ac != NULL)
amr_releasecmd(ac);
- sc->amr_state |= AMR_STATE_INTEN;
-
- return (error);
+ sc->amr_state &= ~AMR_STATE_INTEN;
+ return (error);
}
+
#ifdef AMR_DEBUG
/********************************************************************************
* Print the command (ac) in human-readable format
* 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.
+ * 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.
+ * 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
* 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.
- *
+ */
+/*-
* Copyright (c) 2002 Eric Moore
* Copyright (c) 2002 LSI Logic Corporation
* All rights reserved.
* 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.
+ * 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.
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
* 3. The party using or redistributing the source code and binary forms
- * agrees to the disclaimer below and the terms and conditions set forth
- * herein.
+ * agrees to the disclaimer below and the terms and conditions set forth
+ * herein.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amr_cam.c,v 1.1.2.3 2002/11/11 13:19:10 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amr_cam.c,v 1.11 2008/05/18 20:30:23 pavalos Exp $
+ * $FreeBSD: src/sys/dev/amr/amr_cam.c,v 1.28 2008/11/03 00:53:54 scottl Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/module.h>
-#include "amr_compat.h"
+#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/devicestat.h>
-#include <sys/disk.h>
#include <sys/stat.h>
#include <bus/cam/cam.h>
#include <bus/cam/scsi/scsi_all.h>
#include <bus/cam/scsi/scsi_message.h>
-#include "amrreg.h"
-#include "amrvar.h"
+#include <dev/raid/amr/amrreg.h>
+#include <dev/raid/amr/amrvar.h>
-static void amr_cam_action(struct cam_sim *sim, union ccb *ccb);
-static void amr_cam_poll(struct cam_sim *sim);
-static void amr_cam_complete(struct amr_command *ac);
-static void amr_cam_complete_extcdb(struct amr_command *ac);
+static int amr_cam_probe(device_t dev);
+static int amr_cam_attach(device_t dev);
+static int amr_cam_detach(device_t dev);
+static void amr_cam_action(struct cam_sim *sim, union ccb *ccb);
+static void amr_cam_poll(struct cam_sim *sim);
+static void amr_cam_complete(struct amr_command *ac);
+static int amr_cam_command(struct amr_softc *sc, struct amr_command **acp);
+static devclass_t amr_pass_devclass;
-/********************************************************************************
+static device_method_t amr_pass_methods[] = {
+ DEVMETHOD(device_probe, amr_cam_probe),
+ DEVMETHOD(device_attach, amr_cam_attach),
+ DEVMETHOD(device_detach, amr_cam_detach),
+ { 0, 0 }
+};
+
+static driver_t amr_pass_driver = {
+ "amrp",
+ amr_pass_methods,
+ 0
+};
+
+DRIVER_MODULE(amrp, amr, amr_pass_driver, amr_pass_devclass, 0, 0);
+MODULE_DEPEND(amrp, cam, 1, 1, 1);
+
+MALLOC_DEFINE(M_AMRCAM, "amrcam", "AMR CAM memory");
+
+/***********************************************************************
* Enqueue/dequeue functions
*/
static __inline void
amr_enqueue_ccb(struct amr_softc *sc, union ccb *ccb)
{
- crit_enter();
- TAILQ_INSERT_TAIL(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
- crit_exit();
+
+ TAILQ_INSERT_TAIL(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
}
static __inline void
amr_requeue_ccb(struct amr_softc *sc, union ccb *ccb)
{
- crit_enter();
- TAILQ_INSERT_HEAD(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
- crit_exit();
+
+ TAILQ_INSERT_HEAD(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
}
static __inline union ccb *
amr_dequeue_ccb(struct amr_softc *sc)
{
- union ccb *ccb;
+ union ccb *ccb;
- crit_enter();
- if ((ccb = (union ccb *)TAILQ_FIRST(&sc->amr_cam_ccbq)) != NULL)
- TAILQ_REMOVE(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
- crit_exit();
- return(ccb);
+ if ((ccb = (union ccb *)TAILQ_FIRST(&sc->amr_cam_ccbq)) != NULL)
+ TAILQ_REMOVE(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe);
+ return(ccb);
+}
+
+static int
+amr_cam_probe(device_t dev)
+{
+ return (0);
}
/********************************************************************************
* Attach our 'real' SCSI channels to CAM
*/
-int
-amr_cam_attach(struct amr_softc *sc)
+static int
+amr_cam_attach(device_t dev)
{
- struct cam_devq *devq;
- int chn;
-
- /* initialise the ccb queue */
- TAILQ_INIT(&sc->amr_cam_ccbq);
-
- /*
- * Allocate a devq for all our channels combined. This should
- * allow for the maximum number of SCSI commands we will accept
- * at one time.
- */
- if ((devq = cam_simq_alloc(AMR_MAX_SCSI_CMDS)) == NULL)
- return(ENOMEM);
-
- /*
- * Iterate over our channels, registering them with CAM
- */
- for (chn = 0; chn < sc->amr_maxchan; chn++) {
-
- /* allocate a sim */
- if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action,
- amr_cam_poll,
- "amr",
- sc,
- device_get_unit(sc->amr_dev),
- &sim_mplock,
- 1,
- AMR_MAX_SCSI_CMDS,
- devq)) == NULL) {
- device_printf(sc->amr_dev, "CAM SIM attach failed\n");
- return(ENOMEM);
- }
+ struct amr_softc *sc;
+ struct cam_devq *devq;
+ int chn, error;
- /* register the bus ID so we can get it later */
- if (xpt_bus_register(sc->amr_cam_sim[chn], chn)) {
- device_printf(sc->amr_dev, "CAM XPT bus registration failed\n");
- return(ENXIO);
+ sc = device_get_softc(dev);
+
+ /* initialise the ccb queue */
+ TAILQ_INIT(&sc->amr_cam_ccbq);
+
+ /*
+ * Allocate a devq for all our channels combined. This should
+ * allow for the maximum number of SCSI commands we will accept
+ * at one time. Save the pointer in the softc so we can find it later
+ * during detach.
+ */
+ if ((devq = cam_simq_alloc(AMR_MAX_SCSI_CMDS)) == NULL)
+ return(ENOMEM);
+ sc->amr_cam_devq = devq;
+
+ /*
+ * Iterate over our channels, registering them with CAM
+ */
+ for (chn = 0; chn < sc->amr_maxchan; chn++) {
+
+ /* allocate a sim */
+ if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action,
+ amr_cam_poll, "amr", sc, device_get_unit(sc->amr_dev),
+ &sc->amr_list_lock, 1, AMR_MAX_SCSI_CMDS, devq)) == NULL) {
+ device_printf(sc->amr_dev, "CAM SIM attach failed\n");
+ return(ENOMEM);
+ }
+
+ /* register the bus ID so we can get it later */
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ error = xpt_bus_register(sc->amr_cam_sim[chn], chn);
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+ if (error) {
+ device_printf(sc->amr_dev,
+ "CAM XPT bus registration failed\n");
+ return(ENXIO);
+ }
}
- }
- cam_simq_release(devq);
- /*
- * XXX we should scan the config and work out which devices are actually
- * protected.
- */
- return(0);
+ /*
+ * XXX we should scan the config and work out which devices are
+ * actually protected.
+ */
+ sc->amr_cam_command = amr_cam_command;
+ return(0);
}
/********************************************************************************
* Disconnect ourselves from CAM
*/
-void
-amr_cam_detach(struct amr_softc *sc)
+static int
+amr_cam_detach(device_t dev)
{
- int chn;
-
- /*
- * If a sim was allocated for a channel, free it
- */
- for (chn = 0; chn < sc->amr_maxchan; chn++) {
- if (sc->amr_cam_sim[chn] != NULL) {
- xpt_bus_deregister(cam_sim_path(sc->amr_cam_sim[chn]));
- cam_sim_free(sc->amr_cam_sim[chn]);
+ struct amr_softc *sc;
+ int chn;
+
+ sc = device_get_softc(dev);
+ lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE);
+ for (chn = 0; chn < sc->amr_maxchan; chn++) {
+ /*
+ * If a sim was allocated for this channel, free it
+ */
+ if (sc->amr_cam_sim[chn] != NULL) {
+ xpt_bus_deregister(cam_sim_path(sc->amr_cam_sim[chn]));
+ cam_sim_free(sc->amr_cam_sim[chn]);
+ }
}
- }
+ lockmgr(&sc->amr_list_lock, LK_RELEASE);
+
+ return (0);
}
-/********************************************************************************
- ********************************************************************************
- CAM passthrough interface
- ********************************************************************************
- ********************************************************************************/
+/***********************************************************************
+ ***********************************************************************
+ CAM passthrough interface
+ ***********************************************************************
+ ***********************************************************************/
-/********************************************************************************
+/***********************************************************************
* Handle a request for action from CAM
*/
static void
amr_cam_action(struct cam_sim *sim, union ccb *ccb)
{
- struct amr_softc *sc = cam_sim_softc(sim);
-
- switch(ccb->ccb_h.func_code) {
-
- /*
- * Perform SCSI I/O to a physical device.
- */
- case XPT_SCSI_IO:
- {
- struct ccb_hdr *ccbh = &ccb->ccb_h;
- struct ccb_scsiio *csio = &ccb->csio;
-
- /* Validate the CCB */
- ccbh->status = CAM_REQ_INPROG;
-
- /* check the CDB length */
- if (csio->cdb_len > AMR_MAX_EXTCDB_LEN)
- ccbh->status = CAM_REQ_CMP_ERR;
-
- if ((csio->cdb_len > AMR_MAX_CDB_LEN) && (sc->support_ext_cdb == 0 ))
- ccbh->status = CAM_REQ_CMP_ERR;
-
- /* check that the CDB pointer is not to a physical address */
- if ((ccbh->flags & CAM_CDB_POINTER) && (ccbh->flags & CAM_CDB_PHYS))
- ccbh->status = CAM_REQ_CMP_ERR;
-
- /* if there is data transfer, it must be to/from a virtual address */
- if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
- if (ccbh->flags & CAM_DATA_PHYS) /* we can't map it */
- ccbh->status = CAM_REQ_CMP_ERR;
- if (ccbh->flags & CAM_SCATTER_VALID) /* we want to do the s/g setup */
- ccbh->status = CAM_REQ_CMP_ERR;
+ struct amr_softc *sc = cam_sim_softc(sim);
+
+ switch(ccb->ccb_h.func_code) {
+
+ /*
+ * Perform SCSI I/O to a physical device.
+ */
+ case XPT_SCSI_IO:
+ {
+ struct ccb_hdr *ccbh = &ccb->ccb_h;
+ struct ccb_scsiio *csio = &ccb->csio;
+
+ /* Validate the CCB */
+ ccbh->status = CAM_REQ_INPROG;
+
+ /* check the CDB length */
+ if (csio->cdb_len > AMR_MAX_EXTCDB_LEN)
+ ccbh->status = CAM_REQ_INVALID;
+
+ if ((csio->cdb_len > AMR_MAX_CDB_LEN) &&
+ (sc->support_ext_cdb == 0))
+ ccbh->status = CAM_REQ_INVALID;
+
+ /* check that the CDB pointer is not to a physical address */
+ if ((ccbh->flags & CAM_CDB_POINTER) &&
+ (ccbh->flags & CAM_CDB_PHYS))
+ ccbh->status = CAM_REQ_INVALID;
+ /*
+ * if there is data transfer, it must be to/from a virtual
+ * address
+ */
+ if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if (ccbh->flags & CAM_DATA_PHYS)
+ /* we can't map it */
+ ccbh->status = CAM_REQ_INVALID;
+ if (ccbh->flags & CAM_SCATTER_VALID)
+ /* we want to do the s/g setup */
+ ccbh->status = CAM_REQ_INVALID;
+ }
+
+ /*
+ * If the command is to a LUN other than 0, fail it.
+ * This is probably incorrect, but during testing the
+ * firmware did not seem to respect the LUN field, and thus
+ * devices appear echoed.
+ */
+ if (csio->ccb_h.target_lun != 0)
+ ccbh->status = CAM_DEV_NOT_THERE;
+
+ /* if we're happy with the request, queue it for attention */
+ if (ccbh->status == CAM_REQ_INPROG) {
+
+ /* save the channel number in the ccb */
+ csio->ccb_h.sim_priv.entries[0].field= cam_sim_bus(sim);
+
+ amr_enqueue_ccb(sc, ccb);
+ amr_startio(sc);
+ return;
+ }
+ break;
+ }
+
+ case XPT_CALC_GEOMETRY:
+ {
+ cam_calc_geometry(&ccb->ccg, /*extended*/1);
+ break;
}
/*
- * If the command is to a LUN other than 0, fail it.
- * This is probably incorrect, but during testing the firmware did not
- * seem to respect the LUN field, and thus devices appear echoed.
+ * Return path stats. Some of these should probably be amended.
*/
- if (csio->ccb_h.target_lun != 0)
- ccbh->status = CAM_REQ_CMP_ERR;
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = & ccb->cpi;
+
+ debug(3, "XPT_PATH_INQ");
+ cpi->version_num = 1; /* XXX??? */
+ cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET|PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = AMR_MAX_TARGETS;
+ cpi->max_lun = 0 /* AMR_MAX_LUNS*/;
+ cpi->initiator_id = 7; /* XXX variable? */
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "LSI", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 132 * 1024; /* XXX */
+ cpi->transport = XPORT_SPI;
+ cpi->transport_version = 2;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_2;
+ cpi->ccb_h.status = CAM_REQ_CMP;
- /* if we're happy with the request, queue it for attention */
- if (ccbh->status == CAM_REQ_INPROG) {
+ break;
+ }
- /* save the channel number in the ccb */
- csio->ccb_h.sim_priv.entries[0].field = cam_sim_bus(sim);
+ case XPT_RESET_BUS:
+ {
+ struct ccb_pathinq *cpi = & ccb->cpi;
- amr_enqueue_ccb(sc, ccb);
- amr_startio(sc);
- return;
+ debug(1, "XPT_RESET_BUS");
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
}
- break;
- }
- case XPT_CALC_GEOMETRY:
- {
- struct ccb_calc_geometry *ccg = &ccb->ccg;
- u_int32_t size_in_mb;
- u_int32_t secs_per_cylinder;
+ case XPT_RESET_DEV:
+ {
+ debug(1, "XPT_RESET_DEV");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
- size_in_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size);
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &(ccb->cts);
- if (size_in_mb > 1024) {
- ccg->heads = 255;
- ccg->secs_per_track = 63;
- } else {
- ccg->heads = 64;
- ccg->secs_per_track = 32;
+ debug(3, "XPT_GET_TRAN_SETTINGS");
+
+ struct ccb_trans_settings_scsi *scsi;
+ struct ccb_trans_settings_spi *spi;
+
+ scsi = &cts->proto_specific.scsi;
+ spi = &cts->xport_specific.spi;
+
+ cts->protocol = PROTO_SCSI;
+ cts->protocol_version = SCSI_REV_2;
+ cts->transport = XPORT_SPI;
+ cts->transport_version = 2;
+
+ if (cts->type == CTS_TYPE_USER_SETTINGS) {
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ break;
+ }
+
+ spi->flags = CTS_SPI_FLAGS_DISC_ENB;
+ spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT;
+ spi->sync_period = 6; /* 40MHz how wide is this bus? */
+ spi->sync_offset = 31; /* How to extract this from board? */
+
+ spi->valid = CTS_SPI_VALID_SYNC_RATE
+ | CTS_SPI_VALID_SYNC_OFFSET
+ | CTS_SPI_VALID_BUS_WIDTH
+ | CTS_SPI_VALID_DISC;
+ scsi->valid = CTS_SCSI_VALID_TQ;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
}
- secs_per_cylinder = ccg->heads * ccg->secs_per_track;
- ccg->cylinders = ccg->volume_size / secs_per_cylinder;
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- }
-
- /*
- * Return path stats. Some of these should probably be
- * amended.
- */
- case XPT_PATH_INQ:
- {
- struct ccb_pathinq *cpi = & ccb->cpi;
-
- debug(3, "XPT_PATH_INQ");
- cpi->version_num = 1; /* XXX??? */
- cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
- cpi->target_sprt = 0;
- cpi->hba_misc = PIM_NOBUSRESET;
- cpi->hba_eng_cnt = 0;
- cpi->max_target = AMR_MAX_TARGETS;
- cpi->max_lun = 0 /* AMR_MAX_LUNS*/;
- cpi->initiator_id = 7; /* XXX variable? */
- strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
- strncpy(cpi->hba_vid, "LSI", HBA_IDLEN);
- strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
- cpi->unit_number = cam_sim_unit(sim);
- cpi->bus_id = cam_sim_bus(sim);
- cpi->base_transfer_speed = 132 * 1024; /* XXX get from controller? */
- cpi->transport = XPORT_SPI;
- cpi->transport_version = 2;
- cpi->protocol = PROTO_SCSI;
- cpi->protocol_version = SCSI_REV_2;
- cpi->ccb_h.status = CAM_REQ_CMP;
-
- break;
- }
-
- case XPT_RESET_BUS:
- {
- struct ccb_pathinq *cpi = & ccb->cpi;
-
- debug(1, "XPT_RESET_BUS");
- cpi->ccb_h.status = CAM_REQ_CMP;
- break;
- }
-
- case XPT_RESET_DEV:
- {
- debug(1, "XPT_RESET_DEV");
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- }
-
- case XPT_GET_TRAN_SETTINGS:
- {
- struct ccb_trans_settings *cts = &(ccb->cts);
-
- debug(3, "XPT_GET_TRAN_SETTINGS");
-
- struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
- struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
-
- cts->protocol = PROTO_SCSI;
- cts->protocol_version = SCSI_REV_2;
- cts->transport = XPORT_SPI;
- cts->transport_version = 2;
-
- if (cts->type == CTS_TYPE_USER_SETTINGS) {
+
+ case XPT_SET_TRAN_SETTINGS:
+ debug(3, "XPT_SET_TRAN_SETTINGS");
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
break;
+
+
+ /*
+ * Reject anything else as unsupported.
+ */
+ default:
+ /* we can't do this */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
}
- spi->flags = CTS_SPI_FLAGS_DISC_ENB;
- spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT;
- spi->sync_period = 6; /* 40MHz how wide is this bus? */
- spi->sync_offset = 31; /* How to extract this from board? */
-
- spi->valid = CTS_SPI_VALID_SYNC_RATE
- | CTS_SPI_VALID_SYNC_OFFSET
- | CTS_SPI_VALID_BUS_WIDTH
- | CTS_SPI_VALID_DISC;
- scsi->valid = CTS_SCSI_VALID_TQ;
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- }
-
- case XPT_SET_TRAN_SETTINGS:
- debug(3, "XPT_SET_TRAN_SETTINGS");
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- break;
-
-
- /*
- * Reject anything else as unsupported.
- */
- default:
- /* we can't do this */
- ccb->ccb_h.status = CAM_REQ_INVALID;
- break;
- }
- xpt_done(ccb);
+ KKASSERT(lockstatus(&sc->amr_list_lock, curthread) != 0);
+ xpt_done(ccb);
}
-/********************************************************************************
- * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI command.
+/***********************************************************************
+ * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI
+ * command.
*/
-int
+static int
amr_cam_command(struct amr_softc *sc, struct amr_command **acp)
{
- struct amr_command *ac;
- struct amr_passthrough *ap;
- struct amr_ext_passthrough *aep;
- struct ccb_scsiio *csio;
- int bus, target, error;
-
- error = 0;
- ac = NULL;
- ap = NULL;
- aep = NULL;
-
- /* check to see if there is a ccb for us to work with */
- if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL)
- goto out;
-
- /* get bus/target, XXX validate against protected devices? */
- bus = csio->ccb_h.sim_priv.entries[0].field;
- target = csio->ccb_h.target_id;
-
- /*
- * Build a passthrough command.
- */
-
- /* construct passthrough */
- if (sc->support_ext_cdb ) {
- aep = kmalloc(sizeof(*aep), M_DEVBUF, M_INTWAIT | M_ZERO);
- aep->ap_timeout = 2;
- aep->ap_ars = 1;
- aep->ap_request_sense_length = 14;
- aep->ap_islogical = 0;
- aep->ap_channel = bus;
- aep->ap_scsi_id = target;
- aep->ap_logical_drive_no = csio->ccb_h.target_lun;
- aep->ap_cdb_length = csio->cdb_len;
- aep->ap_data_transfer_length = csio->dxfer_len;
- if (csio->ccb_h.flags & CAM_CDB_POINTER) {
- bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len);
- } else {
- bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb, csio->cdb_len);
- }
- /* we leave the data s/g list and s/g count to the map routine later */
-
- debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0], aep->ap_cdb_length, csio->dxfer_len,
- aep->ap_channel, aep->ap_scsi_id, aep->ap_logical_drive_no);
-
- } else {
- ap = kmalloc(sizeof(*ap), M_DEVBUF, M_INTWAIT | M_ZERO);
- ap->ap_timeout = 0;
- ap->ap_ars = 1;
- ap->ap_request_sense_length = 14;
- ap->ap_islogical = 0;
- ap->ap_channel = bus;
- ap->ap_scsi_id = target;
- ap->ap_logical_drive_no = csio->ccb_h.target_lun;
- ap->ap_cdb_length = csio->cdb_len;
- ap->ap_data_transfer_length = csio->dxfer_len;
- if (csio->ccb_h.flags & CAM_CDB_POINTER) {
- bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len);
- } else {
- bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb, csio->cdb_len);
- }
- /* we leave the data s/g list and s/g count to the map routine later */
-
- debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0], ap->ap_cdb_length, csio->dxfer_len,
- ap->ap_channel, ap->ap_scsi_id, ap->ap_logical_drive_no);
- }
-
- /* construct command */
- if ((ac = amr_alloccmd(sc)) == NULL) {
- error = ENOMEM;
+ struct amr_command *ac;
+ struct amr_passthrough *ap;
+ struct amr_ext_passthrough *aep;
+ struct ccb_scsiio *csio;
+ int bus, target, error;
+
+ error = 0;
+ ac = NULL;
+ ap = NULL;
+ aep = NULL;
+
+ /* check to see if there is a ccb for us to work with */
+ if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL)
goto out;
- }
-
- ac->ac_flags |= AMR_CMD_DATAOUT;
-
- ac->ac_ccb_data = csio->data_ptr;
- ac->ac_ccb_length = csio->dxfer_len;
- if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
- ac->ac_flags |= AMR_CMD_CCB_DATAIN;
- if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
- ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
-
- ac->ac_private = csio;
- if ( sc->support_ext_cdb ) {
- ac->ac_data = aep;
- ac->ac_length = sizeof(*aep);
- ac->ac_complete = amr_cam_complete_extcdb;
- ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS;
- } else {
- ac->ac_data = ap;
- ac->ac_length = sizeof(*ap);
- ac->ac_complete = amr_cam_complete;
- ac->ac_mailbox.mb_command = AMR_CMD_PASS;
- }
-out:
- if (error != 0) {
- if (ac != NULL)
- amr_releasecmd(ac);
- if (ap != NULL)
- kfree(ap, M_DEVBUF);
- if (aep != NULL)
- kfree(aep, M_DEVBUF);
- if (csio != NULL) /* put it back and try again later */
- amr_requeue_ccb(sc, (union ccb *)csio);
- }
- *acp = ac;
- return(error);
-}
-
-/********************************************************************************
- * Check for interrupt status
- */
-static void
-amr_cam_poll(struct cam_sim *sim)
-{
- amr_done(cam_sim_softc(sim));
-}
+ /* get bus/target, XXX validate against protected devices? */
+ bus = csio->ccb_h.sim_priv.entries[0].field;
+ target = csio->ccb_h.target_id;
- /********************************************************************************
- * Handle completion of a command submitted via CAM.
- */
-static void
-amr_cam_complete(struct amr_command *ac)
-{
- struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data;
- struct ccb_scsiio *csio = (struct ccb_scsiio *)ac->ac_private;
- struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr;
-
- /* XXX note that we're ignoring ac->ac_status - good idea? */
+ /*
+ * Build a passthrough command.
+ */
- debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, ap->ap_scsi_status);
+ /* construct command */
+ if ((ac = amr_alloccmd(sc)) == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
- /*
- * Hide disks from CAM so that they're not picked up and treated as 'normal' disks.
- *
- * If the configuration provides a mechanism to mark a disk a "not managed", we
- * could add handling for that to allow disks to be selectively visible.
- */
+ /* construct passthrough */
+ if (sc->support_ext_cdb ) {
+ aep = &ac->ac_ccb->ccb_epthru;
+ aep->ap_timeout = 2;
+ aep->ap_ars = 1;
+ aep->ap_request_sense_length = 14;
+ aep->ap_islogical = 0;
+ aep->ap_channel = bus;
+ aep->ap_scsi_id = target;
+ aep->ap_logical_drive_no = csio->ccb_h.target_lun;
+ aep->ap_cdb_length = csio->cdb_len;
+ aep->ap_data_transfer_length = csio->dxfer_len;
+ if (csio->ccb_h.flags & CAM_CDB_POINTER) {
+ bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len);
+ } else {
+ bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb,
+ csio->cdb_len);
+ }
+ /*
+ * we leave the data s/g list and s/g count to the map routine
+ * later
+ */
+
+ debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0],
+ aep->ap_cdb_length, csio->dxfer_len, aep->ap_channel,
+ aep->ap_scsi_id, aep->ap_logical_drive_no);
- if ((ap->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) {
- bzero(csio->data_ptr, csio->dxfer_len);
- if (ap->ap_scsi_status == 0xf0) {
- csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
} else {
- csio->ccb_h.status = CAM_DEV_NOT_THERE;
+ ap = &ac->ac_ccb->ccb_pthru;
+ ap->ap_timeout = 0;
+ ap->ap_ars = 1;
+ ap->ap_request_sense_length = 14;
+ ap->ap_islogical = 0;
+ ap->ap_channel = bus;
+ ap->ap_scsi_id = target;
+ ap->ap_logical_drive_no = csio->ccb_h.target_lun;
+ ap->ap_cdb_length = csio->cdb_len;
+ ap->ap_data_transfer_length = csio->dxfer_len;
+ if (csio->ccb_h.flags & CAM_CDB_POINTER) {
+ bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len);
+ } else {
+ bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb,
+ csio->cdb_len);
+ }
+ /*
+ * we leave the data s/g list and s/g count to the map routine
+ * later
+ */
+
+ debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0],
+ ap->ap_cdb_length, csio->dxfer_len, ap->ap_channel,
+ ap->ap_scsi_id, ap->ap_logical_drive_no);
}
- } else {
- /* handle passthrough SCSI status */
- switch(ap->ap_scsi_status) {
- case 0: /* completed OK */
- csio->ccb_h.status = CAM_REQ_CMP;
- break;
+ ac->ac_flags |= AMR_CMD_CCB;
- case 0x02:
- csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
- csio->scsi_status = SCSI_STATUS_CHECK_COND;
- bcopy(ap->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN);
- csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
- csio->ccb_h.status |= CAM_AUTOSNS_VALID;
- break;
+ ac->ac_data = csio->data_ptr;
+ ac->ac_length = csio->dxfer_len;
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ ac->ac_flags |= AMR_CMD_DATAIN;
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
+ ac->ac_flags |= AMR_CMD_DATAOUT;
- case 0x08:
- csio->ccb_h.status = CAM_SCSI_BUSY;
- break;
+ ac->ac_private = csio;
+ ac->ac_complete = amr_cam_complete;
+ if ( sc->support_ext_cdb ) {
+ ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS;
+ } else {
+ ac->ac_mailbox.mb_command = AMR_CMD_PASS;
+ }
- case 0xf0:
- case 0xf4:
- default:
- csio->ccb_h.status = CAM_REQ_CMP_ERR;
- break;
+out:
+ if (error != 0) {
+ if (ac != NULL)
+ amr_releasecmd(ac);
+ if (csio != NULL)
+ /* put it back and try again later */
+ amr_requeue_ccb(sc, (union ccb *)csio);
}
- }
- kfree(ap, M_DEVBUF);
- if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
- debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " ");
- xpt_done((union ccb *)csio);
- amr_releasecmd(ac);
+ *acp = ac;
+ return(error);
}
-/********************************************************************************
- * Handle completion of a command submitted via CAM.
- * Completion for extended cdb
+/***********************************************************************
+ * Check for interrupt status
*/
static void
-amr_cam_complete_extcdb(struct amr_command *ac)
+amr_cam_poll(struct cam_sim *sim)
{
- struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data;
- struct ccb_scsiio *csio = (struct ccb_scsiio *)ac->ac_private;
- struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr;
-
- /* XXX note that we're ignoring ac->ac_status - good idea? */
-
- debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status);
- /*
- * Hide disks from CAM so that they're not picked up and treated as 'normal' disks.
- *
- * If the configuration provides a mechanism to mark a disk a "not managed", we
- * could add handling for that to allow disks to be selectively visible.
- */
+ amr_done(cam_sim_softc(sim));
+}
- if ((aep->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) {
- bzero(csio->data_ptr, csio->dxfer_len);
- if (aep->ap_scsi_status == 0xf0) {
- csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
- } else {
- csio->ccb_h.status = CAM_DEV_NOT_THERE;
+ /**********************************************************************
+ * Handle completion of a command submitted via CAM.
+ */
+static void
+amr_cam_complete(struct amr_command *ac)
+{
+ struct amr_passthrough *ap;
+ struct amr_ext_passthrough *aep;
+ struct ccb_scsiio *csio;
+ struct scsi_inquiry_data *inq;
+ int scsi_status, cdb0;
+
+ ap = &ac->ac_ccb->ccb_pthru;
+ aep = &ac->ac_ccb->ccb_epthru;
+ csio = (struct ccb_scsiio *)ac->ac_private;
+ inq = (struct scsi_inquiry_data *)csio->data_ptr;
+
+ if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
+ scsi_status = aep->ap_scsi_status;
+ else
+ scsi_status = ap->ap_scsi_status;
+ debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status,
+ scsi_status);
+
+ /* Make sure the status is sane */
+ if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) {
+ csio->ccb_h.status = CAM_REQ_CMP_ERR;
+ goto out;
}
- } else {
+
+ /*
+ * Hide disks from CAM so that they're not picked up and treated as
+ * 'normal' disks.
+ *
+ * If the configuration provides a mechanism to mark a disk a "not
+ * managed", we could add handling for that to allow disks to be
+ * selectively visible.
+ */
/* handle passthrough SCSI status */
- switch(aep->ap_scsi_status) {
- case 0: /* completed OK */
- csio->ccb_h.status = CAM_REQ_CMP;
- break;
+ switch(scsi_status) {
+ case 0: /* completed OK */
+ if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
+ cdb0 = aep->ap_cdb[0];
+ else
+ cdb0 = ap->ap_cdb[0];
+ if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
+ inq->device = (inq->device & 0xe0) | T_NODEVICE;
+ csio->ccb_h.status = CAM_REQ_CMP;
+ break;
case 0x02:
- csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
- csio->scsi_status = SCSI_STATUS_CHECK_COND;
- bcopy(aep->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN);
- csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
- csio->ccb_h.status |= CAM_AUTOSNS_VALID;
- break;
+ csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ csio->scsi_status = SCSI_STATUS_CHECK_COND;
+ if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
+ bcopy(aep->ap_request_sense_area, &csio->sense_data,
+ AMR_MAX_REQ_SENSE_LEN);
+ else
+ bcopy(ap->ap_request_sense_area, &csio->sense_data,
+ AMR_MAX_REQ_SENSE_LEN);
+ csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ break;
case 0x08:
- csio->ccb_h.status = CAM_SCSI_BUSY;
- break;
+ csio->ccb_h.status = CAM_SCSI_BUSY;
+ break;
case 0xf0:
case 0xf4:
default:
- csio->ccb_h.status = CAM_REQ_CMP_ERR;
- break;
+ /*
+ * Non-zero LUNs are already filtered, so there's no need
+ * to return CAM_DEV_NOT_THERE.
+ */
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ break;
}
- }
- kfree(aep, M_DEVBUF);
- if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
- debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " ");
- xpt_done((union ccb *)csio);
- amr_releasecmd(ac);
+
+out:
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
+ debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr,
+ " ");
+
+ lockmgr(&ac->ac_sc->amr_list_lock, LK_EXCLUSIVE);
+ xpt_done((union ccb *)csio);
+ amr_releasecmd(ac);
+ lockmgr(&ac->ac_sc->amr_list_lock, LK_RELEASE);
}
--- /dev/null
+# $FreeBSD: src/sys/modules/amr/amr_cam/Makefile,v 1.1 2008/11/03 04:13:27 scottl Exp $
+
+.PATH: ${.CURDIR}/..
+
+KMOD= amr_cam
+SRCS= amr_cam.c device_if.h bus_if.h
+SRCS+= opt_cam.h opt_scsi.h
+
+.include <bsd.kmod.mk>
+++ /dev/null
-/*-
- * Copyright (c) 2000 Michael Smith
- * Copyright (c) 2000 BSDi
- * 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.
- *
- * Copyright (c) 2002 Eric Moore
- * Copyright (c) 2002 LSI Logic Corporation
- * 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.
- * 3. The party using or redistributing the source code and binary forms
- * agrees to the disclaimer below and the terms and conditions set forth
- * herein.
- *
- * 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: src/sys/dev/amr/amr_compat.h,v 1.2.2.4 2002/11/11 13:19:10 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amr_compat.h,v 1.7 2006/02/17 19:18:05 dillon Exp $
- */
-
-#include <sys/proc.h>
-#include <sys/buf.h>
-#include <machine/clock.h>
-#include <sys/buf2.h>
-
-#ifndef __packed
-#define __packed __attribute__ ((packed))
-#endif
* 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.
- *
+ */
+/*-
* Copyright (c) 2002 Eric Moore
* Copyright (c) 2002 LSI Logic Corporation
* All rights reserved.
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amr_disk.c,v 1.5.2.5 2002/12/20 15:12:04 emoore Exp $
+ * $FreeBSD: src/sys/dev/amr/amr_disk.c,v 1.39 2006/10/31 21:19:25 pjd Exp $
*/
/*
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/module.h>
-#include "amr_compat.h"
+#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/devicestat.h>
-#include <sys/disk.h>
#include <sys/dtype.h>
-#include <sys/rman.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
-#include <machine/md_var.h>
+#include <sys/rman.h>
-#include "amrio.h"
-#include "amrreg.h"
-#include "amrvar.h"
-#include "amr_tables.h"
+#include <dev/raid/amr/amrio.h>
+#include <dev/raid/amr/amrreg.h>
+#include <dev/raid/amr/amrvar.h>
+#include <dev/raid/amr/amr_tables.h>
/* prototypes */
static int amrd_probe(device_t dev);
static int amrd_detach(device_t dev);
static d_open_t amrd_open;
-static d_close_t amrd_close;
static d_strategy_t amrd_strategy;
-static d_ioctl_t amrd_ioctl;
static d_dump_t amrd_dump;
static struct dev_ops amrd_ops = {
{ "amrd", 0, D_DISK },
.d_open = amrd_open,
- .d_close = amrd_close,
- .d_read = physread,
- .d_write = physwrite,
- .d_ioctl = amrd_ioctl,
.d_strategy = amrd_strategy,
- .d_dump = amrd_dump
+ .d_dump = amrd_dump,
};
static devclass_t amrd_devclass;
+#ifdef FREEBSD_4
+int amr_disks_registered = 0;
+#endif
static device_method_t amrd_methods[] = {
DEVMETHOD(device_probe, amrd_probe),
static int
amrd_open(struct dev_open_args *ap)
{
- cdev_t dev = ap->a_head.a_dev;
- struct amrd_softc *sc = (struct amrd_softc *)dev->si_drv1;
+ struct amrd_softc *sc = ap->a_head.a_dev->si_drv1;
debug_called(1);
/* controller not active? */
if (sc->amrd_controller->amr_state & AMR_STATE_SHUTDOWN)
return(ENXIO);
-#if 0
- bzero(&info, sizeof(info));
- info.d_media_blksize = AMR_BLKSIZE; /* optional */
- info.d_media_blocks = sc->amrd_drive->al_size;
- info.d_type = DTYPE_SCSI; /* mandatory */
- info.d_secpertrack = sc->amrd_drive->al_sectors;
- info.d_nheads = sc->amrd_drive->al_heads;
- info.d_ncylinders = sc->amrd_drive->al_cylinders;
- info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads;
-
- disk_setdiskinfo(&sc->amrd_disk, &info);
-#endif
- sc->amrd_flags |= AMRD_OPEN;
return (0);
}
-
-static int
-amrd_close(struct dev_close_args *ap)
-{
- cdev_t dev = ap->a_head.a_dev;
- struct amrd_softc *sc = (struct amrd_softc *)dev->si_drv1;
-
- debug_called(1);
-
- if (sc == NULL)
- return (ENXIO);
- sc->amrd_flags &= ~AMRD_OPEN;
- return (0);
-}
-
-static int
-amrd_ioctl(struct dev_ioctl_args *ap)
-{
- return (ENOTTY);
-}
-
-
/********************************************************************************
* System crashdump support
*/
-int
+
+static int
amrd_dump(struct dev_dump_args *ap)
{
cdev_t dev = ap->a_head.a_dev;
- struct amrd_softc *amrd_sc = (struct amrd_softc *)dev->si_drv1;
+ off_t offset = ap->a_offset;
+ void *virtual = ap->a_virtual;
+ size_t length = ap->a_length;
+ struct amrd_softc *amrd_sc;
struct amr_softc *amr_sc;
- int error = 0;
- int driveno;
+ int error;
- debug_called(1);
-
- amr_sc = (struct amr_softc *)amrd_sc->amrd_controller;
-
- if (!amrd_sc || !amr_sc)
+ amrd_sc = (struct amrd_softc *)dev->si_drv1;
+ if (amrd_sc == NULL)
return(ENXIO);
+ amr_sc = (struct amr_softc *)amrd_sc->amrd_controller;
- driveno = amrd_sc->amrd_drive - amr_sc->amr_drive;
-
- if (ap->a_length > 0) {
- if ((error = amr_dump_blocks(amr_sc,driveno,ap->a_offset / AMR_BLKSIZE,
- (void *)ap->a_virtual,(int) ap->a_length / AMR_BLKSIZE )) != 0)
+ if (length > 0) {
+ int driveno = amrd_sc->amrd_drive - amr_sc->amr_drive;
+ if ((error = amr_dump_blocks(amr_sc,driveno,offset / AMR_BLKSIZE ,(void *)virtual,(int) length / AMR_BLKSIZE )) != 0)
return(error);
+
}
return(0);
-
}
+
/*
* Read/write routine for a buffer. Finds the proper unit, range checks
* arguments, and schedules the transfer. Does not wait for the transfer
devstat_start_transaction(&sc->amrd_stats);
amr_submit_bio(sc->amrd_controller, bio);
- return(0);
+ return (0);
bad:
bp->b_flags |= B_ERROR;
*/
bp->b_resid = bp->b_bcount;
biodone(bio);
- return(0);
+ return (0);
}
void
-amrd_intr(struct bio *bio)
+amrd_intr(void *data)
{
+ struct bio *bio = (struct bio *)data;
struct buf *bp = bio->bio_buf;
debug_called(2);
} else {
bp->b_resid = 0;
}
+
biodone(bio);
}
static int
amrd_attach(device_t dev)
{
- struct disk_info info;
struct amrd_softc *sc = (struct amrd_softc *)device_get_softc(dev);
device_t parent;
-
+ struct disk_info info;
+
debug_called(1);
parent = device_get_parent(dev);
/* set maximum I/O size to match the maximum s/g size */
sc->amrd_dev_t->si_iosize_max = (AMR_NSEG - 1) * PAGE_SIZE;
- /*
- * Set disk info, as it appears that all needed data is available already.
- * Setting the disk info will also cause the probing to start.
- */
- bzero(&info, sizeof(info));
+ /*
+ * Set disk info, as it appears that all needed data is available already.
+ * Setting the disk info will also cause the probing to start.
+ */
+ bzero(&info, sizeof(info));
info.d_media_blksize = AMR_BLKSIZE; /* optional */
- info.d_media_blocks = sc->amrd_drive->al_size;
+ info.d_media_blocks = sc->amrd_drive->al_size;
- info.d_type = DTYPE_SCSI; /* mandatory */
+ info.d_type = DTYPE_SCSI; /* mandatory */
info.d_secpertrack = sc->amrd_drive->al_sectors;
- info.d_nheads = sc->amrd_drive->al_heads;
+ info.d_nheads = sc->amrd_drive->al_heads;
info.d_ncylinders = sc->amrd_drive->al_cylinders;
- info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads;
+ info.d_secpercyl = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads;
disk_setdiskinfo(&sc->amrd_disk, &info);
debug_called(1);
- if (sc->amrd_flags & AMRD_OPEN)
+#if 0 /* XXX swildner */
+ if (sc->amrd_disk->d_flags & DISKFLAG_OPEN)
return(EBUSY);
+#endif
devstat_remove_entry(&sc->amrd_stats);
+#ifdef FREEBSD_4
+ if (--amr_disks_registered == 0)
+ cdevsw_remove(&amrddisk_cdevsw);
+#else
disk_destroy(&sc->amrd_disk);
+#endif
return(0);
}
--- /dev/null
+/*-
+ * Copyright (c) 2005 Paul Saab
+ * 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: src/sys/dev/amr/amr_linux.c,v 1.5 2009/05/20 17:29:21 imp Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <emulation/linux/i386/linux.h>
+#include <emulation/linux/i386/linux_proto.h>
+#endif
+#include <emulation/linux/linux_ioctl.h>
+
+/* There are multiple ioctl number ranges that need to be handled */
+#define AMR_LINUX_IOCTL_MIN 0x6d00
+#define AMR_LINUX_IOCTL_MAX 0x6d01
+
+static linux_ioctl_function_t amr_linux_ioctl;
+static struct linux_ioctl_handler amr_linux_handler = {amr_linux_ioctl,
+ AMR_LINUX_IOCTL_MIN,
+ AMR_LINUX_IOCTL_MAX};
+
+SYSINIT (amr_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_register_handler, &amr_linux_handler);
+SYSUNINIT(amr_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_unregister_handler, &amr_linux_handler);
+
+static int
+amr_linux_modevent(module_t mod, int cmd, void *data)
+{
+ return (0);
+}
+
+DEV_MODULE(amr_linux, amr_linux_modevent, NULL);
+MODULE_DEPEND(amr, linux, 1, 1, 1);
+
+static int
+amr_linux_ioctl(struct thread *p, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+
+ if ((error = fget(p, args->fd, &fp)) != 0)
+ return (error);
+ error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p);
+ fdrop(fp, p);
+ return (error);
+}
--- /dev/null
+# $FreeBSD: src/sys/modules/amr/amr_linux/Makefile,v 1.1 2006/01/24 21:13:49 ambrisko Exp $
+
+.PATH: ${.CURDIR}/..
+
+KMOD= amr_linux
+SRCS= amr_linux.c device_if.h bus_if.h
+
+.include <bsd.kmod.mk>
* 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.
- *
+ */
+/*-
* Copyright (c) 2002 Eric Moore
- * Copyright (c) 2002 LSI Logic Corporation
+ * Copyright (c) 2002, 2004 LSI Logic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amr_pci.c,v 1.1.2.9 2002/12/20 15:12:04 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amr_pci.c,v 1.9 2006/12/22 23:26:23 swildner Exp $
+ * $FreeBSD: src/sys/dev/amr/amr_pci.c,v 1.40 2007/12/12 05:55:03 scottl Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
-#include "amr_compat.h"
+#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/devicestat.h>
-#include <sys/disk.h>
+
#include <sys/rman.h>
#include <bus/pci/pcireg.h>
#include <bus/pci/pcivar.h>
-#include "amrio.h"
-#include "amrreg.h"
-#include "amrvar.h"
+#include <dev/raid/amr/amrio.h>
+#include <dev/raid/amr/amrreg.h>
+#include <dev/raid/amr/amrvar.h>
static int amr_pci_probe(device_t dev);
static int amr_pci_attach(device_t dev);
static int amr_pci_resume(device_t dev);
static void amr_pci_intr(void *arg);
static void amr_pci_free(struct amr_softc *sc);
-static void amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
+static void amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
static int amr_sglist_map(struct amr_softc *sc);
-static void amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
static int amr_setup_mbox(struct amr_softc *sc);
+static int amr_ccb_map(struct amr_softc *sc);
+
+static u_int amr_force_sg32 = 0;
+TUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32);
+SYSCTL_DECL(_hw_amr);
+SYSCTL_UINT(_hw_amr, OID_AUTO, force_sg32, CTLFLAG_RD, &amr_force_sg32, 0,
+ "Force the AMR driver to use 32bit scatter gather");
static device_method_t amr_methods[] = {
/* Device interface */
static devclass_t amr_devclass;
DRIVER_MODULE(amr, pci, amr_pci_driver, amr_devclass, 0, 0);
+MODULE_DEPEND(amr, pci, 1, 1, 1);
+MODULE_DEPEND(amr, cam, 1, 1, 1);
-static struct
+static struct amr_ident
{
int vendor;
int device;
- int flag;
-#define PROBE_SIGNATURE (1<<0)
+ int flags;
+#define AMR_ID_PROBE_SIG (1<<0) /* generic i960RD, check signature */
+#define AMR_ID_DO_SG64 (1<<1)
+#define AMR_ID_QUARTZ (1<<2)
} amr_device_ids[] = {
{0x101e, 0x9010, 0},
{0x101e, 0x9060, 0},
- {0x8086, 0x1960, PROBE_SIGNATURE},/* generic i960RD, check for signature */
- {0x101e, 0x1960, 0},
- {0x1000, 0x1960, PROBE_SIGNATURE},
- {0x1000, 0x0407, 0},
- {0x1028, 0x000e, PROBE_SIGNATURE}, /* perc4/di i960 */
- {0x1028, 0x000f, 0}, /* perc4/di Verde*/
+ {0x8086, 0x1960, AMR_ID_QUARTZ | AMR_ID_PROBE_SIG},
+ {0x101e, 0x1960, AMR_ID_QUARTZ},
+ {0x1000, 0x1960, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG},
+ {0x1000, 0x0407, AMR_ID_QUARTZ | AMR_ID_DO_SG64},
+ {0x1000, 0x0408, AMR_ID_QUARTZ | AMR_ID_DO_SG64},
+ {0x1000, 0x0409, AMR_ID_QUARTZ | AMR_ID_DO_SG64},
+ {0x1028, 0x000e, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, /* perc4/di i960 */
+ {0x1028, 0x000f, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di Verde*/
+ {0x1028, 0x0013, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di */
{0, 0, 0}
};
-static int
-amr_pci_probe(device_t dev)
+static struct amr_ident *
+amr_find_ident(device_t dev)
{
- int i, sig;
-
- debug_called(1);
+ struct amr_ident *id;
+ int sig;
- for (i = 0; amr_device_ids[i].vendor != 0; i++) {
- if ((pci_get_vendor(dev) == amr_device_ids[i].vendor) &&
- (pci_get_device(dev) == amr_device_ids[i].device)) {
+ for (id = amr_device_ids; id->vendor != 0; id++) {
+ if ((pci_get_vendor(dev) == id->vendor) &&
+ (pci_get_device(dev) == id->device)) {
/* do we need to test for a signature? */
- if (amr_device_ids[i].flag & PROBE_SIGNATURE) {
+ if (id->flags & AMR_ID_PROBE_SIG) {
sig = pci_read_config(dev, AMR_CFG_SIG, 2);
if ((sig != AMR_SIGNATURE_1) && (sig != AMR_SIGNATURE_2))
continue;
}
- device_set_desc(dev, "LSILogic MegaRAID");
- return(-10); /* allow room to be overridden */
+ return (id);
}
}
+ return (NULL);
+}
+
+static int
+amr_pci_probe(device_t dev)
+{
+
+ debug_called(1);
+
+ if (amr_find_ident(dev) != NULL) {
+ device_set_desc(dev, LSI_DESC_PCI);
+ return(BUS_PROBE_DEFAULT);
+ }
return(ENXIO);
}
amr_pci_attach(device_t dev)
{
struct amr_softc *sc;
+ struct amr_ident *id;
int rid, rtype, error;
u_int32_t command;
/*
* Determine board type.
*/
+ if ((id = amr_find_ident(dev)) == NULL)
+ return (ENXIO);
+
command = pci_read_config(dev, PCIR_COMMAND, 1);
- if ((pci_get_device(dev) == 0x1960) || (pci_get_device(dev) == 0x0407) ||
- (pci_get_device(dev) == 0x000e) || (pci_get_device(dev) == 0x000f)) {
+ if (id->flags & AMR_ID_QUARTZ) {
/*
* Make sure we are going to be able to talk to this board.
*/
if ((command & PCIM_CMD_MEMEN) == 0) {
device_printf(dev, "memory window not available\n");
- goto out;
+ return (ENXIO);
}
sc->amr_type |= AMR_TYPE_QUARTZ;
-
} else {
/*
* Make sure we are going to be able to talk to this board.
*/
if ((command & PCIM_CMD_PORTEN) == 0) {
device_printf(dev, "I/O window not available\n");
- goto out;
+ return (ENXIO);
}
}
+ if ((amr_force_sg32 == 0) && (id->flags & AMR_ID_DO_SG64) &&
+ (sizeof(vm_paddr_t) > 4)) {
+ device_printf(dev, "Using 64-bit DMA\n");
+ sc->amr_type |= AMR_TYPE_SG64;
+ }
+
/* force the busmaster enable bit on */
if (!(command & PCIM_CMD_BUSMASTEREN)) {
device_printf(dev, "busmaster bit not set, enabling\n");
/*
* Allocate the PCI register window.
*/
- rid = PCIR_MAPS;
+ rid = PCIR_BAR(0);
rtype = AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT;
- sc->amr_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE);
+ sc->amr_reg = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
if (sc->amr_reg == NULL) {
device_printf(sc->amr_dev, "can't allocate register window\n");
goto out;
* Allocate and connect our interrupt.
*/
rid = 0;
- sc->amr_irq = bus_alloc_resource(sc->amr_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
if (sc->amr_irq == NULL) {
device_printf(sc->amr_dev, "can't allocate interrupt\n");
goto out;
}
- error = bus_setup_intr(sc->amr_dev, sc->amr_irq,
- 0, amr_pci_intr, sc,
- &sc->amr_intr, NULL);
- if (error) {
+ if (bus_setup_intr(sc->amr_dev, sc->amr_irq,
+ 0, amr_pci_intr,
+ sc, &sc->amr_intr, NULL)) {
device_printf(sc->amr_dev, "can't set up interrupt\n");
goto out;
}
* Allocate the parent bus DMA tag appropriate for PCI.
*/
if (bus_dma_tag_create(NULL, /* parent */
- 1, 0, /* alignment, boundary */
+ 1, 0, /* alignment,boundary */
+ AMR_IS_SG64(sc) ?
+ BUS_SPACE_MAXADDR :
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
- BUS_DMA_ALLOCNOW, /* flags */
+ 0, /* flags */
&sc->amr_parent_dmat)) {
device_printf(dev, "can't allocate parent DMA tag\n");
goto out;
* Create DMA tag for mapping buffers into controller-addressable space.
*/
if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
+ 1, 0, /* alignment,boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */
- BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
- 0, /* flags */
+ MAXBSIZE, /* maxsegsize */
+ 0, /* flags */
&sc->amr_buffer_dmat)) {
device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n");
goto out;
}
+ if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
+ 1, 0, /* alignment,boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */
+ MAXBSIZE, /* maxsegsize */
+ 0, /* flags */
+ &sc->amr_buffer64_dmat)) {
+ device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n");
+ goto out;
+ }
+
debug(2, "dma tag done");
/*
* Allocate and set up mailbox in a bus-visible fashion.
*/
+ lockinit(&sc->amr_list_lock, "AMR List Lock", 0, LK_CANRECURSE);
+ lockinit(&sc->amr_hw_lock, "AMR HW Lock", 0, LK_CANRECURSE);
if ((error = amr_setup_mbox(sc)) != 0)
goto out;
*/
if (amr_sglist_map(sc))
goto out;
-
debug(2, "s/g list mapped");
+ if (amr_ccb_map(sc))
+ goto out;
+ debug(2, "ccb mapped");
+
+
/*
* Do bus-independant initialisation, bring controller online.
*/
device_printf(sc->amr_dev, "flushing cache...");
kprintf("%s\n", amr_flush(sc) ? "failed" : "done");
- crit_enter();
error = 0;
/* delete all our child devices */
/* XXX disable interrupts? */
shutdown_out:
- crit_exit();
return(error);
}
{
struct amr_softc *sc = (struct amr_softc *)arg;
- debug_called(2);
+ debug_called(3);
/* collect finished commands, queue anything waiting */
amr_done(sc);
static void
amr_pci_free(struct amr_softc *sc)
{
- u_int8_t *p;
-
+ void *p;
+
debug_called(1);
amr_free(sc);
/* destroy data-transfer DMA tag */
if (sc->amr_buffer_dmat)
bus_dma_tag_destroy(sc->amr_buffer_dmat);
+ if (sc->amr_buffer64_dmat)
+ bus_dma_tag_destroy(sc->amr_buffer64_dmat);
+
+ /* free and destroy DMA memory and tag for passthrough pool */
+ if (sc->amr_ccb)
+ bus_dmamem_free(sc->amr_ccb_dmat, sc->amr_ccb, sc->amr_ccb_dmamap);
+ if (sc->amr_ccb_dmat)
+ bus_dma_tag_destroy(sc->amr_ccb_dmat);
/* free and destroy DMA memory and tag for s/g lists */
if (sc->amr_sgtable)
bus_dma_tag_destroy(sc->amr_sg_dmat);
/* free and destroy DMA memory and tag for mailbox */
+ p = (void *)(uintptr_t)(volatile void *)sc->amr_mailbox64;
if (sc->amr_mailbox) {
- p = (u_int8_t *)(uintptr_t)(volatile void *)sc->amr_mailbox;
- bus_dmamem_free(sc->amr_mailbox_dmat, p - 16, sc->amr_mailbox_dmamap);
+ bus_dmamem_free(sc->amr_mailbox_dmat, p, sc->amr_mailbox_dmamap);
}
if (sc->amr_mailbox_dmat)
bus_dma_tag_destroy(sc->amr_mailbox_dmat);
if (sc->amr_reg != NULL)
bus_release_resource(sc->amr_dev,
AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT,
- PCIR_MAPS, sc->amr_reg);
+ PCIR_BAR(0), sc->amr_reg);
}
/********************************************************************************
* Allocate and map the scatter/gather table in bus space.
*/
static void
-amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
- struct amr_softc *sc = (struct amr_softc *)arg;
+ uint32_t *addr;
debug_called(1);
- /* save base of s/g table's address in bus space */
- sc->amr_sgbusaddr = segs->ds_addr;
+ addr = arg;
+ *addr = segs[0].ds_addr;
}
static int
amr_sglist_map(struct amr_softc *sc)
{
size_t segsize;
+ void *p;
int error;
debug_called(1);
* Create a single tag describing a region large enough to hold all of
* the s/g lists we will need.
*
- * Note that we could probably use AMR_LIMITCMD here, but that may become tunable.
+ * Note that we could probably use AMR_LIMITCMD here, but that may become
+ * tunable.
*/
- segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD;
+ if (AMR_IS_SG64(sc))
+ segsize = sizeof(struct amr_sg64entry) * AMR_NSEG * AMR_MAXCMD;
+ else
+ segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD;
+
error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
+ 512, 0, /* alignment,boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
segsize, 1, /* maxsize, nsegments */
* controller-visible space.
*
* XXX this assumes we can get enough space for all the s/g maps in one
- * contiguous slab. We may need to switch to a more complex arrangement where
- * we allocate in smaller chunks and keep a lookup table from slot to bus address.
+ * contiguous slab. We may need to switch to a more complex arrangement
+ * where we allocate in smaller chunks and keep a lookup table from slot
+ * to bus address.
*
- * XXX HACK ALERT: at least some controllers don't like the s/g memory being
- * allocated below 0x2000. We leak some memory if we get some
- * below this mark and allocate again. We should be able to
- * avoid this with the tag setup, but that does't seem to work.
+ * XXX HACK ALERT: at least some controllers don't like the s/g memory
+ * being allocated below 0x2000. We leak some memory if
+ * we get some below this mark and allocate again. We
+ * should be able to avoid this with the tag setup, but
+ * that does't seem to work.
*/
retry:
- error = bus_dmamem_alloc(sc->amr_sg_dmat, (void *)&sc->amr_sgtable, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap);
+ error = bus_dmamem_alloc(sc->amr_sg_dmat, (void **)&p, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap);
if (error) {
device_printf(sc->amr_dev, "can't allocate s/g table\n");
return(ENOMEM);
}
- bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, sc->amr_sgtable, segsize, amr_sglist_map_helper, sc, 0);
+ bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_helper, &sc->amr_sgbusaddr, 0);
if (sc->amr_sgbusaddr < 0x2000) {
debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr);
goto retry;
}
+
+ if (AMR_IS_SG64(sc))
+ sc->amr_sg64table = (struct amr_sg64entry *)p;
+ sc->amr_sgtable = (struct amr_sgentry *)p;
+
return(0);
}
/********************************************************************************
* Allocate and set up mailbox areas for the controller (sc)
*
- * The basic mailbox structure should be 16-byte aligned. This means that the
- * mailbox64 structure has 4 bytes hanging off the bottom.
+ * The basic mailbox structure should be 16-byte aligned.
*/
-static void
-amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
- struct amr_softc *sc = (struct amr_softc *)arg;
-
- debug_called(1);
-
- /* save phsyical base of the basic mailbox structure */
- sc->amr_mailboxphys = segs->ds_addr + 16;
-}
-
static int
amr_setup_mbox(struct amr_softc *sc)
{
int error;
- u_int8_t *p;
+ void *p;
+ uint32_t baddr;
debug_called(1);
* mailbox.
*/
error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
- 16, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
+ 16, 0, /* alignment,boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- sizeof(struct amr_mailbox) + 16, 1, /* maxsize, nsegments */
+ sizeof(struct amr_mailbox64), /* maxsize */
+ 1, /* nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
0, /* flags */
&sc->amr_mailbox_dmat);
* Allocate the mailbox structure and permanently map it into
* controller-visible space.
*/
- error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void *)&p, BUS_DMA_NOWAIT,
+ error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void **)&p, BUS_DMA_NOWAIT,
&sc->amr_mailbox_dmamap);
if (error) {
device_printf(sc->amr_dev, "can't allocate mailbox memory\n");
return(ENOMEM);
}
- bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p,
- sizeof(struct amr_mailbox64), amr_setup_mbox_helper, sc, 0);
+ bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p,
+ sizeof(struct amr_mailbox64), amr_sglist_helper, &baddr, 0);
/*
* Conventional mailbox is inside the mailbox64 region.
*/
+ /* save physical base of the basic mailbox structure */
+ sc->amr_mailboxphys = baddr + offsetof(struct amr_mailbox64, mb);
bzero(p, sizeof(struct amr_mailbox64));
- sc->amr_mailbox64 = (struct amr_mailbox64 *)(p + 12);
- sc->amr_mailbox = (struct amr_mailbox *)(p + 16);
+ sc->amr_mailbox64 = (struct amr_mailbox64 *)p;
+ sc->amr_mailbox = &sc->amr_mailbox64->mb;
return(0);
}
+
+static int
+amr_ccb_map(struct amr_softc *sc)
+{
+ int ccbsize, error;
+
+ /*
+ * Passthrough and Extended passthrough structures will share the same
+ * memory.
+ */
+ ccbsize = sizeof(union amr_ccb) * AMR_MAXCMD;
+ error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
+ 128, 0, /* alignment,boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ccbsize, /* maxsize */
+ 1, /* nsegments */
+ ccbsize, /* maxsegsize */
+ 0, /* flags */
+ &sc->amr_ccb_dmat);
+ if (error != 0) {
+ device_printf(sc->amr_dev, "can't allocate ccb tag\n");
+ return (ENOMEM);
+ }
+
+ error = bus_dmamem_alloc(sc->amr_ccb_dmat, (void **)&sc->amr_ccb,
+ BUS_DMA_NOWAIT, &sc->amr_ccb_dmamap);
+ if (error) {
+ device_printf(sc->amr_dev, "can't allocate ccb memory\n");
+ return (ENOMEM);
+ }
+ bus_dmamap_load(sc->amr_ccb_dmat, sc->amr_ccb_dmamap, sc->amr_ccb,
+ ccbsize, amr_sglist_helper, &sc->amr_ccb_busaddr, 0);
+ bzero(sc->amr_ccb, ccbsize);
+
+ return (0);
+}
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amr_tables.h,v 1.1.2.3 2002/11/11 13:19:10 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amr_tables.h,v 1.2 2003/06/17 04:28:22 dillon Exp $
+ *
+ * $FreeBSD: src/sys/dev/amr/amr_tables.h,v 1.3 2002/10/30 22:00:11 emoore Exp $
*/
/*
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amrio.h,v 1.2.2.3 2002/11/11 13:19:10 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amrio.h,v 1.2 2003/06/17 04:28:22 dillon Exp $
+ *
+ * $FreeBSD: src/sys/dev/amr/amrio.h,v 1.7 2005/12/14 03:26:49 scottl Exp $
*/
/*
*/
#include <sys/ioccom.h>
+#include <sys/param.h>
/*
* Fetch the driver's interface version.
*/
-#define AMR_IO_VERSION_NUMBER 0x01
+#define AMR_IO_VERSION_NUMBER 153
#define AMR_IO_VERSION _IOR('A', 0x200, int)
/*
#define AMR_IO_COMMAND _IOWR('A', 0x201, struct amr_user_ioctl)
+#if defined(__amd64__) || defined(__ia64__)
+
+struct amr_user_ioctl32 {
+ unsigned char au_cmd[32]; /* command text from userspace */
+ u_int32_t au_buffer; /* 32-bit pointer to uspace buf */
+ u_int32_t au_length; /* length of the uspace buffer */
+ int32_t au_direction; /* data transfer direction */
+ int32_t au_status; /* command status returned by adapter */
+};
+
+# define AMR_IO_COMMAND32 _IOWR('A', 0x201, struct amr_user_ioctl32)
+#endif
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amrreg.h,v 1.1.2.4 2002/11/11 13:19:10 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amrreg.h,v 1.2 2003/06/17 04:28:22 dillon Exp $
+ *
+ * $FreeBSD: src/sys/dev/amr/amrreg.h,v 1.12 2008/02/06 14:26:31 scottl Exp $
*/
/********************************************************************************
#define AMR_LIMITCMD 120 /* maximum count of outstanding commands */
#define AMR_MAXLD 40
-#define AMR_MAX_CHANNELS 4
+#define AMR_MAX_CHANNELS 8
#define AMR_MAX_TARGETS 15
#define AMR_MAX_LUNS 7
#define AMR_MAX_SCSI_CMDS (15 * AMR_MAX_CHANNELS) /* one for every target? */
#define AMR_CMD_GET_MACHINEID 0x36
#define AMR_CMD_GET_INITIATOR 0x7d /* returns one byte */
#define AMR_CMD_CONFIG 0xa1
+#define AMR_CMD_LREAD64 0xa7
+#define AMR_CMD_LWRITE64 0xa8
+#define AMR_CMD_PASS_64 0xc3
+#define AMR_CMD_EXTPASS 0xe3
+
+#define AMR_CONFIG_READ_NVRAM_CONFIG 0x04
+#define AMR_CONFIG_WRITE_NVRAM_CONFIG 0x0d
#define AMR_CONFIG_PRODUCT_INFO 0x0e
#define AMR_CONFIG_ENQ3 0x0f
#define AMR_CONFIG_ENQ3_SOLICITED_NOTIFY 0x01
#define AMR_CONFIG_ENQ3_SOLICITED_FULL 0x02
#define AMR_CONFIG_ENQ3_UNSOLICITED 0x03
-#define AMR_CMD_EXTPASS 0xe3
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define FC_DEL_LOGDRV 0xA4
+#define OP_SUP_DEL_LOGDRV 0x2A
+#define OP_GET_LDID_MAP 0x18
+#define OP_DEL_LOGDRV 0x1C
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define FC_DEL_LOGDRV 0xA4
+#define OP_SUP_DEL_LOGDRV 0x2A
+#define OP_GET_LDID_MAP 0x18
+#define OP_DEL_LOGDRV 0x1C
/*
* Command results
u_int16_t ae_opstatus[AMR_40LD_MAXDRIVES / 8]; /* operation status per drive */
u_int32_t ae_drivesize[AMR_40LD_MAXDRIVES]; /* logical drive size */
u_int8_t ae_driveprop[AMR_40LD_MAXDRIVES]; /* logical drive properties */
- u_int8_t ae_drivestate[AMR_40LD_MAXDRIVES]; /* physical drive state */
- u_int16_t ae_driveformat[AMR_40LD_MAXPHYSDRIVES];
+ u_int8_t ae_drivestate[AMR_40LD_MAXDRIVES]; /* logical drive state */
+ u_int8_t ae_pdrivestate[AMR_40LD_MAXPHYSDRIVES]; /* physical drive state */
+ u_int16_t ae_pdriveformat[AMR_40LD_MAXPHYSDRIVES / 16];
u_int8_t ae_targxfer[80]; /* physical drive transfer rates */
u_int8_t res1[263]; /* pad to 1024 bytes */
{
u_int8_t mb_command;
u_int8_t mb_ident;
- u_int16_t mb_blkcount;
+ u_int16_t mb_blkcount; /* u_int8_t opcode */
+ /* u_int8_t subopcode */
u_int32_t mb_lba;
u_int32_t mb_physaddr;
u_int8_t mb_drive;
- u_int8_t mb_nsgelem;
- u_int8_t res1;
- u_int8_t mb_busy;
+ u_int8_t mb_nsgelem; /* u_int8_t rserv[0] */
+ u_int8_t res1; /* u_int8_t rserv[1] */
+ u_int8_t mb_busy; /* u_int8_t rserv[2] */
u_int8_t mb_nstatus;
u_int8_t mb_status;
u_int8_t mb_completed[46];
struct amr_mailbox64
{
- u_int32_t mb64_segment; /* for 64-bit controllers */
+ u_int8_t pad[8]; /* Needed for alignment */
+ u_int32_t sg64_lo; /* S/G pointer for 64-bit commands */
+ u_int32_t sg64_hi; /* S/G pointer for 64-bit commands */
struct amr_mailbox mb;
} __packed;
u_int32_t sg_count;
} __packed;
+struct amr_sg64entry
+{
+ u_int64_t sg_addr;
+ u_int32_t sg_count;
+} __packed;
+
struct amr_passthrough
{
u_int8_t ap_timeout:3;
u_int32_t ap_data_transfer_length;
} __packed;
+struct amr_linux_ioctl {
+ u_int32_t inlen;
+ u_int32_t outlen;
+ union {
+ u_int8_t fca[16];
+ struct {
+ u_int8_t opcode;
+ u_int8_t subopcode;
+ u_int16_t adapno;
+ u_int32_t buffer;
+ u_int8_t pad[4];
+ u_int32_t length;
+ } __packed fcs;
+ } __packed ui;
+ u_int8_t mbox[18];
+ struct amr_passthrough pthru;
+ u_int32_t data;
+ u_int8_t pad[4];
+} __packed;
+
#ifdef _KERNEL
/********************************************************************************
********************************************************************************
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/amr/amrvar.h,v 1.2.2.5 2002/12/20 15:12:04 emoore Exp $
- * $DragonFly: src/sys/dev/raid/amr/amrvar.h,v 1.11 2008/06/10 17:20:49 dillon Exp $
+ *
+ * $FreeBSD: src/sys/dev/amr/amrvar.h,v 1.37 2010/07/28 16:24:11 mdf Exp $
*/
-#include <sys/thread2.h>
+#include <sys/buf2.h>
+#include <sys/devicestat.h>
+#include <sys/disk.h>
+#include <sys/lock.h>
+#include <sys/sysctl.h>
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
-# include <sys/taskqueue.h>
-#endif
+#define LSI_DESC_PCI "LSILogic MegaRAID 1.53"
#ifdef AMR_DEBUG
# define debug(level, fmt, args...) do {if (level <= AMR_DEBUG) kprintf("%s: " fmt "\n", __func__ , ##args);} while(0)
# define debug_called(level) do {if (level <= AMR_DEBUG) kprintf("%s: called\n", __func__);} while(0)
#else
-# define debug(level, fmt, args...)
-# define debug_called(level)
+# define debug(level, fmt, args...) do {} while (0)
+# define debug_called(level) do {} while (0)
#endif
-#define xdebug(fmt, args...) kprintf("%s: " fmt "\n", __func__ , ##args)
+#define xdebug(fmt, args...) printf("%s: " fmt "\n", __func__ , ##args)
/*
* Per-logical-drive datastructure
#define AMR_CMD_CLUSTERSIZE (16 * 1024)
+typedef STAILQ_HEAD(, amr_command) ac_qhead_t;
+typedef STAILQ_ENTRY(amr_command) ac_link_t;
+
+union amr_ccb {
+ struct amr_passthrough ccb_pthru;
+ struct amr_ext_passthrough ccb_epthru;
+ uint8_t bytes[128];
+};
+
/*
* Per-command control structure.
*/
struct amr_command
{
- TAILQ_ENTRY(amr_command) ac_link;
+ ac_link_t ac_link;
struct amr_softc *ac_sc;
u_int8_t ac_slot;
int ac_status; /* command completion status */
+ union {
+ struct amr_sgentry *sg32;
+ struct amr_sg64entry *sg64;
+ } ac_sg;
+ u_int32_t ac_sgbusaddr;
+ u_int32_t ac_sg64_lo;
+ u_int32_t ac_sg64_hi;
struct amr_mailbox ac_mailbox;
int ac_flags;
#define AMR_CMD_DATAIN (1<<0)
#define AMR_CMD_DATAOUT (1<<1)
-#define AMR_CMD_CCB_DATAIN (1<<2)
-#define AMR_CMD_CCB_DATAOUT (1<<3)
+#define AMR_CMD_CCB (1<<2)
#define AMR_CMD_PRIORITY (1<<4)
#define AMR_CMD_MAPPED (1<<5)
#define AMR_CMD_SLEEP (1<<6)
#define AMR_CMD_BUSY (1<<7)
+#define AMR_CMD_SG64 (1<<8)
+#define AC_IS_SG64(ac) ((ac)->ac_flags & AMR_CMD_SG64)
+ u_int ac_retries;
struct bio *ac_bio;
+ void (* ac_complete)(struct amr_command *ac);
+ void *ac_private;
void *ac_data;
size_t ac_length;
bus_dmamap_t ac_dmamap;
- u_int32_t ac_dataphys;
+ bus_dmamap_t ac_dma64map;
- void *ac_ccb_data;
- size_t ac_ccb_length;
- bus_dmamap_t ac_ccb_dmamap;
- u_int32_t ac_ccb_dataphys;
+ bus_dma_tag_t ac_tag;
+ bus_dmamap_t ac_datamap;
+ int ac_nsegments;
+ uint32_t ac_mb_physaddr;
- void (* ac_complete)(struct amr_command *ac);
- void *ac_private;
+ union amr_ccb *ac_ccb;
+ uint32_t ac_ccb_busaddr;
};
struct amr_command_cluster
bus_space_tag_t amr_btag;
bus_dma_tag_t amr_parent_dmat; /* parent DMA tag */
bus_dma_tag_t amr_buffer_dmat; /* data buffer DMA tag */
+ bus_dma_tag_t amr_buffer64_dmat;
struct resource *amr_irq; /* interrupt */
void *amr_intr;
/* scatter/gather lists and their controller-visible mappings */
struct amr_sgentry *amr_sgtable; /* s/g lists */
+ struct amr_sg64entry *amr_sg64table; /* 64bit s/g lists */
u_int32_t amr_sgbusaddr; /* s/g table base address in bus space */
bus_dma_tag_t amr_sg_dmat; /* s/g buffer DMA tag */
bus_dmamap_t amr_sg_dmamap; /* map for s/g buffers */
+ union amr_ccb *amr_ccb;
+ uint32_t amr_ccb_busaddr;
+ bus_dma_tag_t amr_ccb_dmat;
+ bus_dmamap_t amr_ccb_dmamap;
+
/* controller limits and features */
+ int amr_nextslot; /* Next slot to use for newly allocated commands */
int amr_maxio; /* maximum number of I/O transactions */
int amr_maxdrives; /* max number of logical drives */
int amr_maxchan; /* count of SCSI channels */
#define AMR_STATE_SUSPEND (1<<1)
#define AMR_STATE_INTEN (1<<2)
#define AMR_STATE_SHUTDOWN (1<<3)
+#define AMR_STATE_CRASHDUMP (1<<4)
+#define AMR_STATE_QUEUE_FRZN (1<<5)
+#define AMR_STATE_LD_DELETE (1<<6)
+#define AMR_STATE_REMAP_LD (1<<7)
/* per-controller queues */
struct bio_queue_head amr_bioq; /* pending I/O with no commands */
- TAILQ_HEAD(,amr_command) amr_ready; /* commands ready to be submitted */
+ ac_qhead_t amr_ready; /* commands ready to be submitted */
struct amr_command *amr_busycmd[AMR_MAXCMD];
int amr_busyslots;
- TAILQ_HEAD(,amr_command) amr_completed;
- TAILQ_HEAD(,amr_command) amr_freecmds;
+ ac_qhead_t amr_freecmds;
TAILQ_HEAD(,amr_command_cluster) amr_cmd_clusters;
/* CAM attachments for passthrough */
struct cam_sim *amr_cam_sim[AMR_MAX_CHANNELS];
TAILQ_HEAD(, ccb_hdr) amr_cam_ccbq;
+ struct cam_devq *amr_cam_devq;
/* control device */
- cdev_t amr_dev_t;
+ struct cdev *amr_dev_t;
+ struct lock amr_list_lock;
+
+ struct sysctl_ctx_list amr_sysctl_ctx;
+ struct sysctl_oid *amr_sysctl_tree;
/* controller type-specific support */
int amr_type;
#define AMR_IS_QUARTZ(sc) ((sc)->amr_type & AMR_TYPE_QUARTZ)
#define AMR_TYPE_40LD (1<<1)
#define AMR_IS_40LD(sc) ((sc)->amr_type & AMR_TYPE_40LD)
- int (* amr_submit_command)(struct amr_softc *sc);
+#define AMR_TYPE_SG64 (1<<2)
+#define AMR_IS_SG64(sc) ((sc)->amr_type & AMR_TYPE_SG64)
+ int (* amr_submit_command)(struct amr_command *ac);
int (* amr_get_work)(struct amr_softc *sc, struct amr_mailbox *mbsave);
int (*amr_poll_command)(struct amr_command *ac);
+ int (*amr_poll_command1)(struct amr_softc *sc, struct amr_command *ac);
int support_ext_cdb; /* greater than 10 byte cdb support */
/* misc glue */
+ device_t amr_pass;
+ int (*amr_cam_command)(struct amr_softc *sc, struct amr_command **acp);
struct intr_config_hook amr_ich; /* wait-for-interrupts probe hook */
struct callout amr_timeout; /* periodic status check */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
- struct task amr_task_complete; /* deferred-completion task */
-#endif
+ int amr_allow_vol_config;
+ int amr_linux_no_adapters;
+ int amr_ld_del_supported;
+ struct lock amr_hw_lock;
};
/*
extern void amr_releasecmd(struct amr_command *ac);
/*
- * CAM interface
- */
-extern int amr_cam_attach(struct amr_softc *sc);
-extern void amr_cam_detach(struct amr_softc *sc);
-extern int amr_cam_command(struct amr_softc *sc, struct amr_command **acp);
-
-/*
* MegaRAID logical disk driver
*/
struct amrd_softc
struct disk amrd_disk;
struct devstat amrd_stats;
int amrd_unit;
- int amrd_flags;
-#define AMRD_OPEN (1<<0) /* drive is open (can't detach) */
};
/*
* Interface between driver core and disk driver (should be using a bus?)
*/
extern int amr_submit_bio(struct amr_softc *sc, struct bio *bio);
-extern void amrd_intr(struct bio *bio);
-extern int amr_dump_blocks(struct amr_softc *sc, int unit, u_int64_t lba, void *data, int blks);
+extern int amr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks);
+extern void amrd_intr(void *data);
/********************************************************************************
* Enqueue/dequeue functions
static __inline void
amr_enqueue_bio(struct amr_softc *sc, struct bio *bio)
{
- crit_enter();
- bioqdisksort(&sc->amr_bioq, bio);
- crit_exit();
+
+ bioq_insert_tail(&sc->amr_bioq, bio);
}
static __inline struct bio *
{
struct bio *bio;
- crit_enter();
if ((bio = bioq_first(&sc->amr_bioq)) != NULL)
bioq_remove(&sc->amr_bioq, bio);
- crit_exit();
return(bio);
}
static __inline void
+amr_init_qhead(ac_qhead_t *head)
+{
+
+ STAILQ_INIT(head);
+}
+
+static __inline void
amr_enqueue_ready(struct amr_command *ac)
{
- crit_enter();
- TAILQ_INSERT_TAIL(&ac->ac_sc->amr_ready, ac, ac_link);
- crit_exit();
+
+ STAILQ_INSERT_TAIL(&ac->ac_sc->amr_ready, ac, ac_link);
}
static __inline void
amr_requeue_ready(struct amr_command *ac)
{
- crit_enter();
- TAILQ_INSERT_HEAD(&ac->ac_sc->amr_ready, ac, ac_link);
- crit_exit();
+
+ STAILQ_INSERT_HEAD(&ac->ac_sc->amr_ready, ac, ac_link);
}
static __inline struct amr_command *
{
struct amr_command *ac;
- crit_enter();
- if ((ac = TAILQ_FIRST(&sc->amr_ready)) != NULL)
- TAILQ_REMOVE(&sc->amr_ready, ac, ac_link);
- crit_exit();
+ if ((ac = STAILQ_FIRST(&sc->amr_ready)) != NULL)
+ STAILQ_REMOVE_HEAD(&sc->amr_ready, ac_link);
return(ac);
}
static __inline void
-amr_enqueue_completed(struct amr_command *ac)
+amr_enqueue_completed(struct amr_command *ac, ac_qhead_t *head)
{
- crit_enter();
- TAILQ_INSERT_TAIL(&ac->ac_sc->amr_completed, ac, ac_link);
- crit_exit();
+
+ STAILQ_INSERT_TAIL(head, ac, ac_link);
}
static __inline struct amr_command *
-amr_dequeue_completed(struct amr_softc *sc)
+amr_dequeue_completed(struct amr_softc *sc, ac_qhead_t *head)
{
struct amr_command *ac;
- crit_enter();
- if ((ac = TAILQ_FIRST(&sc->amr_completed)) != NULL)
- TAILQ_REMOVE(&sc->amr_completed, ac, ac_link);
- crit_exit();
+ if ((ac = STAILQ_FIRST(head)) != NULL)
+ STAILQ_REMOVE_HEAD(head, ac_link);
return(ac);
}
static __inline void
amr_enqueue_free(struct amr_command *ac)
{
- crit_enter();
- TAILQ_INSERT_TAIL(&ac->ac_sc->amr_freecmds, ac, ac_link);
- crit_exit();
+
+ STAILQ_INSERT_HEAD(&ac->ac_sc->amr_freecmds, ac, ac_link);
}
static __inline struct amr_command *
{
struct amr_command *ac;
- crit_enter();
- if ((ac = TAILQ_FIRST(&sc->amr_freecmds)) != NULL)
- TAILQ_REMOVE(&sc->amr_freecmds, ac, ac_link);
- crit_exit();
+ if ((ac = STAILQ_FIRST(&sc->amr_freecmds)) != NULL)
+ STAILQ_REMOVE_HEAD(&sc->amr_freecmds, ac_link);
return(ac);
}