[Midnightbsd-cvs] src: dev/mfi: merge
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Tue Nov 25 11:45:36 EST 2008
Log Message:
-----------
merge
Modified Files:
--------------
src/sys/dev/mfi:
mfi.c (r1.1 -> r1.2)
mfi_disk.c (r1.1 -> r1.2)
mfi_ioctl.h (r1.1 -> r1.2)
mfi_pci.c (r1.1 -> r1.2)
mfireg.h (r1.1 -> r1.2)
mfivar.h (r1.1 -> r1.2)
Added Files:
-----------
src/sys/dev/mfi:
mfi_cam.c (r1.1)
mfi_debug.c (r1.1)
mfi_linux.c (r1.1)
-------------- next part --------------
Index: mfi_disk.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_disk.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_disk.c -L sys/dev/mfi/mfi_disk.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_disk.c
+++ sys/dev/mfi/mfi_disk.c
@@ -25,16 +25,17 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.2.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.7 2007/08/13 19:29:17 jhb Exp $");
#include "opt_mfi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/selinfo.h>
#include <sys/module.h>
#include <sys/malloc.h>
+#include <sys/uio.h>
#include <sys/bio.h>
#include <sys/bus.h>
@@ -64,15 +65,6 @@
static devclass_t mfi_disk_devclass;
-struct mfi_disk {
- device_t ld_dev;
- int ld_id;
- int ld_unit;
- struct mfi_softc *ld_controller;
- struct mfi_ld *ld_ld;
- struct disk *ld_disk;
-};
-
static device_method_t mfi_disk_methods[] = {
DEVMETHOD(device_probe, mfi_disk_probe),
DEVMETHOD(device_attach, mfi_disk_attach),
@@ -99,31 +91,48 @@
mfi_disk_attach(device_t dev)
{
struct mfi_disk *sc;
- struct mfi_ld *ld;
+ struct mfi_ld_info *ld_info;
uint64_t sectors;
uint32_t secsize;
+ char *state;
sc = device_get_softc(dev);
- ld = device_get_ivars(dev);
+ ld_info = device_get_ivars(dev);
sc->ld_dev = dev;
- sc->ld_id = ld->ld_id;
+ sc->ld_id = ld_info->ld_config.properties.ld.v.target_id;
sc->ld_unit = device_get_unit(dev);
- sc->ld_ld = device_get_ivars(dev);
+ sc->ld_info = ld_info;
sc->ld_controller = device_get_softc(device_get_parent(dev));
+ sc->ld_flags = 0;
- sectors = sc->ld_ld->ld_sectors;
- secsize = sc->ld_ld->ld_secsize;
- if (secsize != MFI_SECTOR_LEN) {
- device_printf(sc->ld_dev, "Reported sector length %d is not "
- "512, aborting\n", secsize);
- free(sc->ld_ld, M_MFIBUF);
- return (EINVAL);
+ sectors = ld_info->size;
+ secsize = MFI_SECTOR_LEN;
+ mtx_lock(&sc->ld_controller->mfi_io_lock);
+ TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
+
+ switch (ld_info->ld_config.params.state) {
+ case MFI_LD_STATE_OFFLINE:
+ state = "offline";
+ break;
+ case MFI_LD_STATE_PARTIALLY_DEGRADED:
+ state = "partially degraded";
+ break;
+ case MFI_LD_STATE_DEGRADED:
+ state = "degraded";
+ break;
+ case MFI_LD_STATE_OPTIMAL:
+ state = "optimal";
+ break;
+ default:
+ state = "unknown";
+ break;
}
- TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, ld, ld_link);
-
- device_printf(dev, "%juMB (%ju sectors) RAID\n",
- sectors / (1024 * 1024 / secsize), sectors);
+ device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n",
+ sectors / (1024 * 1024 / secsize), sectors,
+ ld_info->ld_config.properties.name,
+ state);
sc->ld_disk = disk_alloc();
sc->ld_disk->d_drv1 = sc;
@@ -155,27 +164,79 @@
sc = device_get_softc(dev);
- if (sc->ld_disk->d_flags & DISKFLAG_OPEN)
+ mtx_lock(&sc->ld_controller->mfi_io_lock);
+ if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) ||
+ (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
+ (sc->ld_controller->mfi_keep_deleted_volumes ||
+ sc->ld_controller->mfi_detaching)) {
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
return (EBUSY);
+ }
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
disk_destroy(sc->ld_disk);
+ mtx_lock(&sc->ld_controller->mfi_io_lock);
+ TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
+ free(sc->ld_info, M_MFIBUF);
return (0);
}
static int
mfi_disk_open(struct disk *dp)
{
+ struct mfi_disk *sc;
+ int error;
- return (0);
+ sc = dp->d_drv1;
+ mtx_lock(&sc->ld_controller->mfi_io_lock);
+ if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED)
+ error = ENXIO;
+ else {
+ sc->ld_flags |= MFI_DISK_FLAGS_OPEN;
+ error = 0;
+ }
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
+
+ return (error);
}
static int
mfi_disk_close(struct disk *dp)
{
+ struct mfi_disk *sc;
+
+ sc = dp->d_drv1;
+ mtx_lock(&sc->ld_controller->mfi_io_lock);
+ sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN;
+ mtx_unlock(&sc->ld_controller->mfi_io_lock);
return (0);
}
+int
+mfi_disk_disable(struct mfi_disk *sc)
+{
+
+ mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
+ if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
+ if (sc->ld_controller->mfi_delete_busy_volumes)
+ return (0);
+ device_printf(sc->ld_dev, "Unable to delete busy device\n");
+ return (EBUSY);
+ }
+ sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
+ return (0);
+}
+
+void
+mfi_disk_enable(struct mfi_disk *sc)
+{
+
+ mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
+ sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED;
+}
+
static void
mfi_disk_strategy(struct bio *bio)
{
@@ -234,7 +295,7 @@
if (len > 0) {
if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
- sc->ld_ld->ld_secsize, virt, len)) != 0)
+ MFI_SECTOR_LEN, virt, len)) != 0)
return (error);
} else {
/* mfi_sync_cache(parent_sc, sc->ld_id); */
Index: mfi.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi.c -L sys/dev/mfi/mfi.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi.c
+++ sys/dev/mfi/mfi.c
@@ -23,17 +23,45 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi.c,v 1.3.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi.c,v 1.33.4.1 2008/02/04 14:54:21 ambrisko Exp $");
#include "opt_mfi.h"
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/eventhandler.h>
@@ -41,6 +69,9 @@
#include <sys/bus_dma.h>
#include <sys/bio.h>
#include <sys/ioccom.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -50,31 +81,56 @@
#include <dev/mfi/mfivar.h>
static int mfi_alloc_commands(struct mfi_softc *);
-static void mfi_release_command(struct mfi_command *cm);
static int mfi_comms_init(struct mfi_softc *);
-static int mfi_polled_command(struct mfi_softc *, struct mfi_command *);
+static int mfi_wait_command(struct mfi_softc *, struct mfi_command *);
static int mfi_get_controller_info(struct mfi_softc *);
+static int mfi_get_log_state(struct mfi_softc *,
+ struct mfi_evt_log_state **);
+static int mfi_get_entry(struct mfi_softc *, int);
+static int mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
+ uint32_t, void **, size_t);
static void mfi_data_cb(void *, bus_dma_segment_t *, int, int);
static void mfi_startup(void *arg);
static void mfi_intr(void *arg);
-static void mfi_enable_intr(struct mfi_softc *sc);
-static void mfi_ldprobe_inq(struct mfi_softc *sc);
-static void mfi_ldprobe_inq_complete(struct mfi_command *);
-static int mfi_ldprobe_capacity(struct mfi_softc *sc, int id);
-static void mfi_ldprobe_capacity_complete(struct mfi_command *);
-static int mfi_ldprobe_tur(struct mfi_softc *sc, int id);
-static void mfi_ldprobe_tur_complete(struct mfi_command *);
-static int mfi_add_ld(struct mfi_softc *sc, int id, uint64_t, uint32_t);
+static void mfi_ldprobe(struct mfi_softc *sc);
+static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
+static void mfi_aen_complete(struct mfi_command *);
+static int mfi_aen_setup(struct mfi_softc *, uint32_t);
+static int mfi_add_ld(struct mfi_softc *sc, int);
+static void mfi_add_ld_complete(struct mfi_command *);
static struct mfi_command * mfi_bio_command(struct mfi_softc *);
static void mfi_bio_complete(struct mfi_command *);
static int mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
static int mfi_send_frame(struct mfi_softc *, struct mfi_command *);
static void mfi_complete(struct mfi_softc *, struct mfi_command *);
+static int mfi_abort(struct mfi_softc *, struct mfi_command *);
+static int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
+static void mfi_timeout(void *);
+static void mfi_enable_intr_xscale(struct mfi_softc *sc);
+static void mfi_enable_intr_ppc(struct mfi_softc *sc);
+static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc);
+static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc);
+static int mfi_check_clear_intr_xscale(struct mfi_softc *sc);
+static int mfi_check_clear_intr_ppc(struct mfi_softc *sc);
+static void mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+static void mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+
+SYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
+static int mfi_event_locale = MFI_EVT_LOCALE_ALL;
+TUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
+SYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
+ 0, "event message locale");
+
+static int mfi_event_class = MFI_EVT_CLASS_INFO;
+TUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
+SYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
+ 0, "event message class");
/* Management interface */
static d_open_t mfi_open;
static d_close_t mfi_close;
static d_ioctl_t mfi_ioctl;
+static d_poll_t mfi_poll;
static struct cdevsw mfi_cdevsw = {
.d_version = D_VERSION,
@@ -82,12 +138,76 @@
.d_open = mfi_open,
.d_close = mfi_close,
.d_ioctl = mfi_ioctl,
+ .d_poll = mfi_poll,
.d_name = "mfi",
};
MALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
-#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
+#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
+
+static void
+mfi_enable_intr_xscale(struct mfi_softc *sc)
+{
+ MFI_WRITE4(sc, MFI_OMSK, 0x01);
+}
+
+static void
+mfi_enable_intr_ppc(struct mfi_softc *sc)
+{
+ MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
+ MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
+}
+
+static int32_t
+mfi_read_fw_status_xscale(struct mfi_softc *sc)
+{
+ return MFI_READ4(sc, MFI_OMSG0);
+}
+
+static int32_t
+mfi_read_fw_status_ppc(struct mfi_softc *sc)
+{
+ return MFI_READ4(sc, MFI_OSP0);
+}
+
+static int
+mfi_check_clear_intr_xscale(struct mfi_softc *sc)
+{
+ int32_t status;
+
+ status = MFI_READ4(sc, MFI_OSTS);
+ if ((status & MFI_OSTS_INTR_VALID) == 0)
+ return 1;
+
+ MFI_WRITE4(sc, MFI_OSTS, status);
+ return 0;
+ }
+
+static int
+mfi_check_clear_intr_ppc(struct mfi_softc *sc)
+{
+ int32_t status;
+
+ status = MFI_READ4(sc, MFI_OSTS);
+ if (!status)
+ return 1;
+
+ MFI_WRITE4(sc, MFI_ODCR0, status);
+ return 0;
+ }
+
+static void
+mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+{
+ MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
+}
+
+static void
+mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+{
+ MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
+}
static int
mfi_transition_firmware(struct mfi_softc *sc)
@@ -95,11 +215,11 @@
int32_t fw_state, cur_state;
int max_wait, i;
- fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
+ fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK;
while (fw_state != MFI_FWSTATE_READY) {
if (bootverbose)
device_printf(sc->mfi_dev, "Waiting for firmware to "
- "become ready\n");
+ "become ready\n");
cur_state = fw_state;
switch (fw_state) {
case MFI_FWSTATE_FAULT:
@@ -128,7 +248,7 @@
return (ENXIO);
}
for (i = 0; i < (max_wait * 10); i++) {
- fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
+ fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
if (fw_state == cur_state)
DELAY(100000);
else
@@ -157,16 +277,34 @@
{
uint32_t status;
int error, commsz, framessz, sensesz;
- int frames, unit;
+ int frames, unit, max_fw_sge;
+ device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 2.00 \n");
mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
+ sx_init(&sc->mfi_config_lock, "MFI config");
TAILQ_INIT(&sc->mfi_ld_tqh);
+ TAILQ_INIT(&sc->mfi_aen_pids);
+ TAILQ_INIT(&sc->mfi_cam_ccbq);
mfi_initq_free(sc);
mfi_initq_ready(sc);
mfi_initq_busy(sc);
mfi_initq_bio(sc);
+ if (sc->mfi_flags & MFI_FLAGS_1064R) {
+ sc->mfi_enable_intr = mfi_enable_intr_xscale;
+ sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
+ sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
+ sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
+ }
+ else {
+ sc->mfi_enable_intr = mfi_enable_intr_ppc;
+ sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
+ sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
+ sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
+ }
+
+
/* Before we get too far, see if the firmware is working */
if ((error = mfi_transition_firmware(sc)) != 0) {
device_printf(sc->mfi_dev, "Firmware not in READY state, "
@@ -181,10 +319,10 @@
* It would be nice if these constants were available at runtime
* instead of compile time.
*/
- status = MFI_READ4(sc, MFI_OMSG0);
+ status = sc->mfi_read_fw_status(sc);
sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
- sc->mfi_max_fw_sgl = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
- sc->mfi_total_sgl = min(sc->mfi_max_fw_sgl, ((MAXPHYS / PAGE_SIZE) +1));
+ max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
+ sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
/*
* Create the dma tag for data buffers. Used both for block I/O
@@ -196,7 +334,7 @@
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
- sc->mfi_total_sgl, /* nsegments */
+ sc->mfi_max_sge, /* nsegments */
BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
busdma_lock_mutex, /* lockfunc */
@@ -239,24 +377,23 @@
/*
* Allocate DMA memory for the command frames. Keep them in the
- * lower 4GB for efficiency. Calculate the size of the frames at
- * the same time; the frame is 64 bytes plus space for the SG lists.
+ * lower 4GB for efficiency. Calculate the size of the commands at
+ * the same time; each command is one 64 byte frame plus a set of
+ * additional frames for holding sg lists or other data.
* The assumption here is that the SG list will start at the second
- * 64 byte segment of the frame and not use the unused bytes in the
- * frame. While this might seem wasteful, apparently the frames must
- * be 64 byte aligned, so any savings would be negated by the extra
- * alignment padding.
+ * frame and not use the unused bytes in the first frame. While this
+ * isn't technically correct, it simplifies the calculation and allows
+ * for command frames that might be larger than an mfi_io_frame.
*/
if (sizeof(bus_addr_t) == 8) {
- sc->mfi_sgsize = sizeof(struct mfi_sg64);
+ sc->mfi_sge_size = sizeof(struct mfi_sg64);
sc->mfi_flags |= MFI_FLAGS_SG64;
} else {
- sc->mfi_sgsize = sizeof(struct mfi_sg32);
+ sc->mfi_sge_size = sizeof(struct mfi_sg32);
}
- frames = (sc->mfi_sgsize * sc->mfi_total_sgl + MFI_FRAME_SIZE - 1) /
- MFI_FRAME_SIZE + 1;
- sc->mfi_frame_size = frames * MFI_FRAME_SIZE;
- framessz = sc->mfi_frame_size * sc->mfi_max_fw_cmds;
+ frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
+ sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
+ framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
64, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -316,10 +453,12 @@
if ((error = mfi_get_controller_info(sc)) != 0)
return (error);
-#if 0
- if ((error = mfi_setup_aen(sc)) != 0)
+ mtx_lock(&sc->mfi_io_lock);
+ if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
-#endif
+ }
+ mtx_unlock(&sc->mfi_io_lock);
/*
* Set up the interrupt handler. XXX This should happen in
@@ -332,7 +471,7 @@
return (EINVAL);
}
if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
- mfi_intr, sc, &sc->mfi_intr)) {
+ NULL, mfi_intr, sc, &sc->mfi_intr)) {
device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
return (EINVAL);
}
@@ -361,8 +500,27 @@
unit = device_get_unit(sc->mfi_dev);
sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
0640, "mfi%d", unit);
+ if (unit == 0)
+ make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
if (sc->mfi_cdev != NULL)
sc->mfi_cdev->si_drv1 = sc;
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
+ OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
+ &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
+ OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
+ &sc->mfi_keep_deleted_volumes, 0,
+ "Don't detach the mfid device for a busy volume that is deleted");
+
+ device_add_child(sc->mfi_dev, "mfip", -1);
+ bus_generic_attach(sc->mfi_dev);
+
+ /* Start the timeout watchdog */
+ callout_init(&sc->mfi_watchdog_callout, 1);
+ callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+ mfi_timeout, sc);
return (0);
}
@@ -383,14 +541,15 @@
for (i = 0; i < ncmds; i++) {
cm = &sc->mfi_commands[i];
- cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
- sc->mfi_frame_size * i);
+ cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
+ sc->mfi_cmd_size * i);
cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
- sc->mfi_frame_size * i;
+ sc->mfi_cmd_size * i;
cm->cm_frame->header.context = i;
cm->cm_sense = &sc->mfi_sense[i];
cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
cm->cm_sc = sc;
+ cm->cm_index = i;
if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
&cm->cm_dmamap) == 0)
mfi_release_command(cm);
@@ -402,29 +561,88 @@
return (0);
}
-static void
+void
mfi_release_command(struct mfi_command *cm)
{
+ struct mfi_frame_header *hdr;
uint32_t *hdr_data;
/*
* Zero out the important fields of the frame, but make sure the
- * context field is preserved
+ * context field is preserved. For efficiency, handle the fields
+ * as 32 bit words. Clear out the first S/G entry too for safety.
*/
+ hdr = &cm->cm_frame->header;
+ if (cm->cm_data != NULL && hdr->sg_count) {
+ cm->cm_sg->sg32[0].len = 0;
+ cm->cm_sg->sg32[0].addr = 0;
+ }
+
hdr_data = (uint32_t *)cm->cm_frame;
- hdr_data[0] = 0;
- hdr_data[1] = 0;
+ hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */
+ hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */
+ hdr_data[4] = 0; /* flags, timeout */
+ hdr_data[5] = 0; /* data_len */
cm->cm_extra_frames = 0;
cm->cm_flags = 0;
cm->cm_complete = NULL;
cm->cm_private = NULL;
+ cm->cm_data = NULL;
cm->cm_sg = 0;
cm->cm_total_frame_size = 0;
+
mfi_enqueue_free(cm);
}
static int
+mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
+ void **bufp, size_t bufsize)
+{
+ struct mfi_command *cm;
+ struct mfi_dcmd_frame *dcmd;
+ void *buf = NULL;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ cm = mfi_dequeue_free(sc);
+ if (cm == NULL)
+ return (EBUSY);
+
+ if ((bufsize > 0) && (bufp != NULL)) {
+ if (*bufp == NULL) {
+ buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
+ if (buf == NULL) {
+ mfi_release_command(cm);
+ return (ENOMEM);
+ }
+ *bufp = buf;
+ } else {
+ buf = *bufp;
+ }
+ }
+
+ dcmd = &cm->cm_frame->dcmd;
+ bzero(dcmd->mbox, MFI_MBOX_SIZE);
+ dcmd->header.cmd = MFI_CMD_DCMD;
+ dcmd->header.timeout = 0;
+ dcmd->header.flags = 0;
+ dcmd->header.data_len = bufsize;
+ dcmd->opcode = opcode;
+ cm->cm_sg = &dcmd->sgl;
+ cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+ cm->cm_flags = 0;
+ cm->cm_data = buf;
+ cm->cm_private = buf;
+ cm->cm_len = bufsize;
+
+ *cmp = cm;
+ if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
+ *bufp = buf;
+ return (0);
+}
+
+static int
mfi_comms_init(struct mfi_softc *sc)
{
struct mfi_command *cm;
@@ -432,6 +650,7 @@
struct mfi_init_qinfo *qinfo;
int error;
+ mtx_lock(&sc->mfi_io_lock);
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
@@ -454,12 +673,16 @@
init->header.cmd = MFI_CMD_INIT;
init->header.data_len = sizeof(struct mfi_init_qinfo);
init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
+ cm->cm_data = NULL;
+ cm->cm_flags = MFI_CMD_POLLED;
- if ((error = mfi_polled_command(sc, cm)) != 0) {
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "failed to send init command\n");
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
}
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
return (0);
}
@@ -467,48 +690,24 @@
static int
mfi_get_controller_info(struct mfi_softc *sc)
{
- struct mfi_command *cm;
- struct mfi_dcmd_frame *dcmd;
- struct mfi_ctrl_info *ci;
+ struct mfi_command *cm = NULL;
+ struct mfi_ctrl_info *ci = NULL;
uint32_t max_sectors_1, max_sectors_2;
int error;
- if ((cm = mfi_dequeue_free(sc)) == NULL)
- return (EBUSY);
-
- ci = malloc(sizeof(struct mfi_ctrl_info), M_MFIBUF, M_NOWAIT | M_ZERO);
- if (ci == NULL) {
- mfi_release_command(cm);
- return (ENOMEM);
- }
-
- dcmd = &cm->cm_frame->dcmd;
- bzero(dcmd->mbox, MFI_MBOX_SIZE);
- dcmd->header.cmd = MFI_CMD_DCMD;
- dcmd->header.timeout = 0;
- dcmd->header.data_len = sizeof(struct mfi_ctrl_info);
- dcmd->opcode = MFI_DCMD_CTRL_GETINFO;
- cm->cm_sg = &dcmd->sgl;
- cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+ mtx_lock(&sc->mfi_io_lock);
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
+ (void **)&ci, sizeof(*ci));
+ if (error)
+ goto out;
cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
- cm->cm_data = ci;
- cm->cm_len = sizeof(struct mfi_ctrl_info);
if ((error = mfi_mapcmd(sc, cm)) != 0) {
- device_printf(sc->mfi_dev, "Controller info buffer map failed");
- free(ci, M_MFIBUF);
- mfi_release_command(cm);
- return (error);
- }
-
- /* It's ok if this fails, just use default info instead */
- if ((error = mfi_polled_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "Failed to get controller info\n");
- sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
+ sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
MFI_SECTOR_LEN;
- free(ci, M_MFIBUF);
- mfi_release_command(cm);
- return (0);
+ error = 0;
+ goto out;
}
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
@@ -519,37 +718,102 @@
max_sectors_2 = ci->max_request_size;
sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
- free(ci, M_MFIBUF);
- mfi_release_command(cm);
+out:
+ if (ci)
+ free(ci, M_MFIBUF);
+ if (cm)
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ return (error);
+}
+
+static int
+mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
+{
+ struct mfi_command *cm = NULL;
+ int error;
+
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
+ (void **)log_state, sizeof(**log_state));
+ if (error)
+ goto out;
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev, "Failed to get log state\n");
+ goto out;
+ }
+
+ bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+
+out:
+ if (cm)
+ mfi_release_command(cm);
return (error);
}
static int
-mfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
+mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
{
- struct mfi_frame_header *hdr;
- int tm = MFI_POLL_TIMEOUT_SECS * 1000000;
+ struct mfi_evt_log_state *log_state = NULL;
+ union mfi_evt class_locale;
+ int error = 0;
+ uint32_t seq;
+
+ class_locale.members.reserved = 0;
+ class_locale.members.locale = mfi_event_locale;
+ class_locale.members.class = mfi_event_class;
+
+ if (seq_start == 0) {
+ error = mfi_get_log_state(sc, &log_state);
+ if (error) {
+ if (log_state)
+ free(log_state, M_MFIBUF);
+ return (error);
+ }
+ /*
+ * Don't run them yet since we can't parse them.
+ * We can indirectly get the contents from
+ * the AEN mechanism via setting it lower then
+ * current. The firmware will iterate through them.
+ */
+ for (seq = log_state->shutdown_seq_num;
+ seq <= log_state->newest_seq_num; seq++) {
+ mfi_get_entry(sc, seq);
+ }
+ } else
+ seq = seq_start;
+ mfi_aen_register(sc, seq, class_locale.word);
+ free(log_state, M_MFIBUF);
- hdr = &cm->cm_frame->header;
- hdr->cmd_status = 0xff;
- hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+ return 0;
+}
- mfi_send_frame(sc, cm);
+static int
+mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
+{
- while (hdr->cmd_status == 0xff) {
- DELAY(1000);
- tm -= 1000;
- if (tm <= 0)
- break;
- }
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ cm->cm_complete = NULL;
- if (hdr->cmd_status == 0xff) {
- device_printf(sc->mfi_dev, "Frame %p timed out\n", hdr);
- return (ETIMEDOUT);
- }
- return (0);
+ /*
+ * MegaCli can issue a DCMD of 0. In this case do nothing
+ * and return 0 to it as status
+ */
+ if (cm->cm_frame->dcmd.opcode == 0) {
+ cm->cm_frame->header.cmd_status = MFI_STAT_OK;
+ cm->cm_error = 0;
+ return (cm->cm_error);
+ }
+ mfi_enqueue_ready(cm);
+ mfi_startio(sc);
+ if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
+ msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
+ return (cm->cm_error);
}
void
@@ -558,6 +822,8 @@
struct mfi_command *cm;
int i;
+ callout_drain(&sc->mfi_watchdog_callout);
+
if (sc->mfi_cdev != NULL)
destroy_dev(sc->mfi_cdev);
@@ -604,8 +870,10 @@
if (sc->mfi_parent_dmat != NULL)
bus_dma_tag_destroy(sc->mfi_parent_dmat);
- if (mtx_initialized(&sc->mfi_io_lock))
+ if (mtx_initialized(&sc->mfi_io_lock)) {
mtx_destroy(&sc->mfi_io_lock);
+ sx_destroy(&sc->mfi_config_lock);
+ }
return;
}
@@ -619,8 +887,12 @@
config_intrhook_disestablish(&sc->mfi_ich);
- mfi_enable_intr(sc);
- mfi_ldprobe_inq(sc);
+ sc->mfi_enable_intr(sc);
+ sx_xlock(&sc->mfi_config_lock);
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_ldprobe(sc);
+ mtx_unlock(&sc->mfi_io_lock);
+ sx_xunlock(&sc->mfi_config_lock);
}
static void
@@ -628,39 +900,37 @@
{
struct mfi_softc *sc;
struct mfi_command *cm;
- uint32_t status, pi, ci, context;
+ uint32_t pi, ci, context;
sc = (struct mfi_softc *)arg;
- status = MFI_READ4(sc, MFI_OSTS);
- if ((status & MFI_OSTS_INTR_VALID) == 0)
+ if (sc->mfi_check_clear_intr(sc))
return;
- MFI_WRITE4(sc, MFI_OSTS, status);
pi = sc->mfi_comms->hw_pi;
ci = sc->mfi_comms->hw_ci;
-
mtx_lock(&sc->mfi_io_lock);
while (ci != pi) {
context = sc->mfi_comms->hw_reply_q[ci];
- sc->mfi_comms->hw_reply_q[ci] = 0xffffffff;
- if (context == 0xffffffff) {
- device_printf(sc->mfi_dev, "mfi_intr: invalid context "
- "pi= %d ci= %d\n", pi, ci);
- } else {
+ if (context < sc->mfi_max_fw_cmds) {
cm = &sc->mfi_commands[context];
mfi_remove_busy(cm);
+ cm->cm_error = 0;
mfi_complete(sc, cm);
}
- ci++;
- if (ci == (sc->mfi_max_fw_cmds + 1)) {
+ if (++ci == (sc->mfi_max_fw_cmds + 1)) {
ci = 0;
}
}
- mtx_unlock(&sc->mfi_io_lock);
sc->mfi_comms->hw_ci = ci;
+ /* Give defered I/O a chance to run */
+ if (sc->mfi_flags & MFI_FLAGS_QFRZN)
+ sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
+ mfi_startio(sc);
+ mtx_unlock(&sc->mfi_io_lock);
+
return;
}
@@ -671,278 +941,597 @@
struct mfi_command *cm;
int error;
- if ((cm = mfi_dequeue_free(sc)) == NULL)
- return (EBUSY);
+ mtx_lock(&sc->mfi_io_lock);
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
+ if (error) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (error);
+ }
- /* AEN? */
+ if (sc->mfi_aen_cm != NULL)
+ mfi_abort(sc, sc->mfi_aen_cm);
dcmd = &cm->cm_frame->dcmd;
- bzero(dcmd->mbox, MFI_MBOX_SIZE);
- dcmd->header.cmd = MFI_CMD_DCMD;
- dcmd->header.sg_count = 0;
dcmd->header.flags = MFI_FRAME_DIR_NONE;
- dcmd->header.timeout = 0;
- dcmd->header.data_len = 0;
- dcmd->opcode = MFI_DCMD_CTRL_SHUTDOWN;
+ cm->cm_flags = MFI_CMD_POLLED;
+ cm->cm_data = NULL;
- if ((error = mfi_polled_command(sc, cm)) != 0) {
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
}
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
}
static void
-mfi_enable_intr(struct mfi_softc *sc)
+mfi_ldprobe(struct mfi_softc *sc)
{
+ struct mfi_frame_header *hdr;
+ struct mfi_command *cm = NULL;
+ struct mfi_ld_list *list = NULL;
+ struct mfi_disk *ld;
+ int error, i;
- MFI_WRITE4(sc, MFI_OMSK, 0x01);
-}
+ sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
-static void
-mfi_ldprobe_inq(struct mfi_softc *sc)
-{
- struct mfi_command *cm;
- struct mfi_pass_frame *pass;
- char *inq;
- int i;
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
+ (void **)&list, sizeof(*list));
+ if (error)
+ goto out;
- /* Probe all possible targets with a SCSI INQ command */
- mtx_lock(&sc->mfi_io_lock);
- sc->mfi_probe_count = 0;
- for (i = 0; i < MFI_MAX_CHANNEL_DEVS; i++) {
- inq = malloc(MFI_INQ_LENGTH, M_MFIBUF, M_NOWAIT|M_ZERO);
- if (inq == NULL)
- break;
- cm = mfi_dequeue_free(sc);
- if (cm == NULL) {
- tsleep(mfi_startup, 0, "mfistart", 5 * hz);
- i--;
- continue;
- }
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = i;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = MFI_INQ_LENGTH;
- bzero(pass->cdb, 16);
- pass->cdb[0] = INQUIRY;
- pass->cdb[4] = MFI_INQ_LENGTH;
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_inq_complete;
- cm->cm_private = inq;
- cm->cm_sg = &pass->sgl;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags |= MFI_CMD_DATAIN;
- cm->cm_data = inq;
- cm->cm_len = MFI_INQ_LENGTH;
- sc->mfi_probe_count++;
- mfi_enqueue_ready(cm);
- mfi_startio(sc);
+ cm->cm_flags = MFI_CMD_DATAIN;
+ if (mfi_wait_command(sc, cm) != 0) {
+ device_printf(sc->mfi_dev, "Failed to get device listing\n");
+ goto out;
}
- /* Sleep while the arrays are attaching */
- msleep(mfi_startup, &sc->mfi_io_lock, 0, "mfistart", 60 * hz);
- mtx_unlock(&sc->mfi_io_lock);
+ hdr = &cm->cm_frame->header;
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
+ hdr->cmd_status);
+ goto out;
+ }
+
+ for (i = 0; i < list->ld_count; i++) {
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ if (ld->ld_id == list->ld_list[i].ld.v.target_id)
+ goto skip_add;
+ }
+ mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
+ skip_add:;
+ }
+out:
+ if (list)
+ free(list, M_MFIBUF);
+ if (cm)
+ mfi_release_command(cm);
return;
}
static void
-mfi_ldprobe_inq_complete(struct mfi_command *cm)
+mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
{
- struct mfi_frame_header *hdr;
- struct mfi_softc *sc;
- struct scsi_inquiry_data *inq;
-
- sc = cm->cm_sc;
- inq = cm->cm_private;
- hdr = &cm->cm_frame->header;
-
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00) ||
- (SID_TYPE(inq) != T_DIRECT)) {
- free(inq, M_MFIBUF);
- mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
- return;
+ switch (detail->arg_type) {
+ case MR_EVT_ARGS_NONE:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_CDB_SENSE:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) CDB %*D"
+ "Sense %*D\n: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.cdb_sense.pd.device_id,
+ detail->args.cdb_sense.pd.enclosure_index,
+ detail->args.cdb_sense.pd.slot_number,
+ detail->args.cdb_sense.cdb_len,
+ detail->args.cdb_sense.cdb,
+ ":",
+ detail->args.cdb_sense.sense_len,
+ detail->args.cdb_sense.sense,
+ ":",
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "event: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld.ld_index,
+ detail->args.ld.target_id,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_COUNT:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "count %lld: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_count.ld.ld_index,
+ detail->args.ld_count.ld.target_id,
+ (long long)detail->args.ld_count.count,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_LBA:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "lba %lld: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_lba.ld.ld_index,
+ detail->args.ld_lba.ld.target_id,
+ (long long)detail->args.ld_lba.lba,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_OWNER:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "owner changed: prior %d, new %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_owner.ld.ld_index,
+ detail->args.ld_owner.ld.target_id,
+ detail->args.ld_owner.pre_owner,
+ detail->args.ld_owner.new_owner,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_LBA_PD_LBA:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_lba_pd_lba.ld.ld_index,
+ detail->args.ld_lba_pd_lba.ld.target_id,
+ (long long)detail->args.ld_lba_pd_lba.ld_lba,
+ detail->args.ld_lba_pd_lba.pd.device_id,
+ detail->args.ld_lba_pd_lba.pd.enclosure_index,
+ detail->args.ld_lba_pd_lba.pd.slot_number,
+ (long long)detail->args.ld_lba_pd_lba.pd_lba,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_PROG:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "progress %d%% in %ds: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_prog.ld.ld_index,
+ detail->args.ld_prog.ld.target_id,
+ detail->args.ld_prog.prog.progress/655,
+ detail->args.ld_prog.prog.elapsed_seconds,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_STATE:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "state prior %d new %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_state.ld.ld_index,
+ detail->args.ld_state.ld.target_id,
+ detail->args.ld_state.prev_state,
+ detail->args.ld_state.new_state,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_LD_STRIP:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+ "strip %lld: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ld_strip.ld.ld_index,
+ detail->args.ld_strip.ld.target_id,
+ (long long)detail->args.ld_strip.strip,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "event: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd.device_id,
+ detail->args.pd.enclosure_index,
+ detail->args.pd.slot_number,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD_ERR:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "err %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd_err.pd.device_id,
+ detail->args.pd_err.pd.enclosure_index,
+ detail->args.pd_err.pd.slot_number,
+ detail->args.pd_err.err,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD_LBA:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "lba %lld: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd_lba.pd.device_id,
+ detail->args.pd_lba.pd.enclosure_index,
+ detail->args.pd_lba.pd.slot_number,
+ (long long)detail->args.pd_lba.lba,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD_LBA_LD:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "lba %lld VD %02d/%d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd_lba_ld.pd.device_id,
+ detail->args.pd_lba_ld.pd.enclosure_index,
+ detail->args.pd_lba_ld.pd.slot_number,
+ (long long)detail->args.pd_lba.lba,
+ detail->args.pd_lba_ld.ld.ld_index,
+ detail->args.pd_lba_ld.ld.target_id,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD_PROG:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "progress %d%% seconds %ds: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd_prog.pd.device_id,
+ detail->args.pd_prog.pd.enclosure_index,
+ detail->args.pd_prog.pd.slot_number,
+ detail->args.pd_prog.prog.progress/655,
+ detail->args.pd_prog.prog.elapsed_seconds,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PD_STATE:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+ "state prior %d new %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pd_prog.pd.device_id,
+ detail->args.pd_prog.pd.enclosure_index,
+ detail->args.pd_prog.pd.slot_number,
+ detail->args.pd_state.prev_state,
+ detail->args.pd_state.new_state,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_PCI:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PCI 0x04%x 0x04%x "
+ "0x04%x 0x04%x: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.pci.venderId,
+ detail->args.pci.deviceId,
+ detail->args.pci.subVenderId,
+ detail->args.pci.subDeviceId,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_RATE:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Rebuild rate %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.rate,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_TIME:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ticks %d "
+ "elapsed %ds: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.time.rtc,
+ detail->args.time.elapsedSeconds,
+ detail->description
+ );
+ break;
+ case MR_EVT_ARGS_ECC:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ECC %x,%x: %s: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->args.ecc.ecar,
+ detail->args.ecc.elog,
+ detail->args.ecc.str,
+ detail->description
+ );
+ break;
+ default:
+ device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Type %d: %s\n",
+ detail->seq,
+ detail->time,
+ detail->class.members.locale,
+ detail->class.members.class,
+ detail->arg_type, detail->description
+ );
}
-
- free(inq, M_MFIBUF);
- mfi_release_command(cm);
- mfi_ldprobe_tur(sc, hdr->target_id);
}
static int
-mfi_ldprobe_tur(struct mfi_softc *sc, int id)
+mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
{
struct mfi_command *cm;
- struct mfi_pass_frame *pass;
+ struct mfi_dcmd_frame *dcmd;
+ union mfi_evt current_aen, prior_aen;
+ struct mfi_evt_detail *ed = NULL;
+ int error = 0;
+
+ current_aen.word = locale;
+ if (sc->mfi_aen_cm != NULL) {
+ prior_aen.word =
+ ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
+ if (prior_aen.members.class <= current_aen.members.class &&
+ !((prior_aen.members.locale & current_aen.members.locale)
+ ^current_aen.members.locale)) {
+ return (0);
+ } else {
+ prior_aen.members.locale |= current_aen.members.locale;
+ if (prior_aen.members.class
+ < current_aen.members.class)
+ current_aen.members.class =
+ prior_aen.members.class;
+ mfi_abort(sc, sc->mfi_aen_cm);
+ }
+ }
+
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
+ (void **)&ed, sizeof(*ed));
+ if (error) {
+ goto out;
+ }
+
+ dcmd = &cm->cm_frame->dcmd;
+ ((uint32_t *)&dcmd->mbox)[0] = seq;
+ ((uint32_t *)&dcmd->mbox)[1] = locale;
+ cm->cm_flags = MFI_CMD_DATAIN;
+ cm->cm_complete = mfi_aen_complete;
+
+ sc->mfi_aen_cm = cm;
- cm = mfi_dequeue_free(sc);
- if (cm == NULL)
- return (EBUSY);
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = id;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = 0;
- bzero(pass->cdb, 16);
- pass->cdb[0] = TEST_UNIT_READY;
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_tur_complete;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags = 0;
mfi_enqueue_ready(cm);
mfi_startio(sc);
- return (0);
+out:
+ return (error);
}
static void
-mfi_ldprobe_tur_complete(struct mfi_command *cm)
+mfi_aen_complete(struct mfi_command *cm)
{
struct mfi_frame_header *hdr;
struct mfi_softc *sc;
+ struct mfi_evt_detail *detail;
+ struct mfi_aen *mfi_aen_entry, *tmp;
+ int seq = 0, aborted = 0;
sc = cm->cm_sc;
hdr = &cm->cm_frame->header;
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
- device_printf(sc->mfi_dev, "Logical disk %d is not ready, "
- "cmd_status= %d scsi_status= %d\n", hdr->target_id,
- hdr->cmd_status, hdr->scsi_status);
- mfi_print_sense(sc, cm->cm_sense);
- mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
+ if (sc->mfi_aen_cm == NULL)
return;
+
+ if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
+ sc->mfi_aen_cm->cm_aen_abort = 0;
+ aborted = 1;
+ } else {
+ sc->mfi_aen_triggered = 1;
+ if (sc->mfi_poll_waiting) {
+ sc->mfi_poll_waiting = 0;
+ selwakeup(&sc->mfi_select);
+ }
+ detail = cm->cm_data;
+ /*
+ * XXX If this function is too expensive or is recursive, then
+ * events should be put onto a queue and processed later.
+ */
+ mtx_unlock(&sc->mfi_io_lock);
+ mfi_decode_evt(sc, detail);
+ mtx_lock(&sc->mfi_io_lock);
+ seq = detail->seq + 1;
+ TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
+ TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+ aen_link);
+ PROC_LOCK(mfi_aen_entry->p);
+ psignal(mfi_aen_entry->p, SIGIO);
+ PROC_UNLOCK(mfi_aen_entry->p);
+ free(mfi_aen_entry, M_MFIBUF);
+ }
}
+
+ free(cm->cm_data, M_MFIBUF);
+ sc->mfi_aen_cm = NULL;
+ wakeup(&sc->mfi_aen_cm);
mfi_release_command(cm);
- mfi_ldprobe_capacity(sc, hdr->target_id);
+
+ /* set it up again so the driver can catch more events */
+ if (!aborted) {
+ mfi_aen_setup(sc, seq);
+ }
}
+/* Only do one event for now so we can easily iterate through them */
+#define MAX_EVENTS 1
static int
-mfi_ldprobe_capacity(struct mfi_softc *sc, int id)
+mfi_get_entry(struct mfi_softc *sc, int seq)
{
struct mfi_command *cm;
- struct mfi_pass_frame *pass;
- struct scsi_read_capacity_data_long *cap;
+ struct mfi_dcmd_frame *dcmd;
+ struct mfi_evt_list *el;
+ int error;
+ int i;
+ int size;
- cap = malloc(sizeof(*cap), M_MFIBUF, M_NOWAIT|M_ZERO);
- if (cap == NULL)
- return (ENOMEM);
- cm = mfi_dequeue_free(sc);
- if (cm == NULL)
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
return (EBUSY);
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = id;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = sizeof(*cap);
- bzero(pass->cdb, 16);
- pass->cdb[0] = 0x9e; /* READ CAPACITY 16 */
- pass->cdb[13] = sizeof(*cap);
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_capacity_complete;
- cm->cm_private = cap;
- cm->cm_sg = &pass->sgl;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags |= MFI_CMD_DATAIN;
- cm->cm_data = cap;
- cm->cm_len = sizeof(*cap);
- mfi_enqueue_ready(cm);
- mfi_startio(sc);
+ }
- return (0);
-}
+ size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
+ * (MAX_EVENTS - 1);
+ el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
+ if (el == NULL) {
+ mfi_release_command(cm);
+ return (ENOMEM);
+ }
-static void
-mfi_ldprobe_capacity_complete(struct mfi_command *cm)
-{
- struct mfi_frame_header *hdr;
- struct mfi_softc *sc;
- struct scsi_read_capacity_data_long *cap;
- uint64_t sectors;
- uint32_t secsize;
- int target;
-
- sc = cm->cm_sc;
- cap = cm->cm_private;
- hdr = &cm->cm_frame->header;
+ dcmd = &cm->cm_frame->dcmd;
+ bzero(dcmd->mbox, MFI_MBOX_SIZE);
+ dcmd->header.cmd = MFI_CMD_DCMD;
+ dcmd->header.timeout = 0;
+ dcmd->header.data_len = size;
+ dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
+ ((uint32_t *)&dcmd->mbox)[0] = seq;
+ ((uint32_t *)&dcmd->mbox)[1] = MFI_EVT_LOCALE_ALL;
+ cm->cm_sg = &dcmd->sgl;
+ cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+ cm->cm_data = el;
+ cm->cm_len = size;
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
- device_printf(sc->mfi_dev, "Failed to read capacity for "
- "logical disk\n");
- device_printf(sc->mfi_dev, "cmd_status= %d scsi_status= %d\n",
- hdr->cmd_status, hdr->scsi_status);
- free(cap, M_MFIBUF);
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev, "Failed to get controller entry\n");
+ sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
+ MFI_SECTOR_LEN;
+ free(el, M_MFIBUF);
mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
- return;
+ return (0);
}
- target = hdr->target_id;
- sectors = scsi_8btou64(cap->addr);
- secsize = scsi_4btoul(cap->length);
- free(cap, M_MFIBUF);
- mfi_release_command(cm);
- mfi_add_ld(sc, target, sectors, secsize);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
- return;
+ bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+
+ if (dcmd->header.cmd_status != MFI_STAT_NOT_FOUND) {
+ for (i = 0; i < el->count; i++) {
+ if (seq + i == el->event[i].seq)
+ mfi_decode_evt(sc, &el->event[i]);
+ }
+ }
+
+ free(cm->cm_data, M_MFIBUF);
+ mfi_release_command(cm);
+ return (0);
}
static int
-mfi_add_ld(struct mfi_softc *sc, int id, uint64_t sectors, uint32_t secsize)
+mfi_add_ld(struct mfi_softc *sc, int id)
{
- struct mfi_ld *ld;
- device_t child;
+ struct mfi_command *cm;
+ struct mfi_dcmd_frame *dcmd = NULL;
+ struct mfi_ld_info *ld_info = NULL;
+ int error;
- if ((secsize == 0) || (sectors == 0)) {
- device_printf(sc->mfi_dev, "Invalid capacity parameters for "
- "logical disk %d\n", id);
- return (EINVAL);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
+ (void **)&ld_info, sizeof(*ld_info));
+ if (error) {
+ device_printf(sc->mfi_dev,
+ "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
+ if (ld_info)
+ free(ld_info, M_MFIBUF);
+ return (error);
+ }
+ cm->cm_flags = MFI_CMD_DATAIN;
+ dcmd = &cm->cm_frame->dcmd;
+ dcmd->mbox[0] = id;
+ if (mfi_wait_command(sc, cm) != 0) {
+ device_printf(sc->mfi_dev,
+ "Failed to get logical drive: %d\n", id);
+ free(ld_info, M_MFIBUF);
+ return (0);
}
- ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
- if (ld == NULL) {
- device_printf(sc->mfi_dev, "Cannot allocate ld\n");
- return (ENOMEM);
+ mfi_add_ld_complete(cm);
+ return (0);
+}
+
+static void
+mfi_add_ld_complete(struct mfi_command *cm)
+{
+ struct mfi_frame_header *hdr;
+ struct mfi_ld_info *ld_info;
+ struct mfi_softc *sc;
+ device_t child;
+
+ sc = cm->cm_sc;
+ hdr = &cm->cm_frame->header;
+ ld_info = cm->cm_private;
+
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ free(ld_info, M_MFIBUF);
+ mfi_release_command(cm);
+ return;
}
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ mtx_lock(&Giant);
if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
device_printf(sc->mfi_dev, "Failed to add logical disk\n");
- return (EINVAL);
+ free(ld_info, M_MFIBUF);
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+ return;
}
- ld->ld_id = id;
- ld->ld_disk = child;
- ld->ld_secsize = secsize;
- ld->ld_sectors = sectors;
-
- device_set_ivars(child, ld);
+ device_set_ivars(child, ld_info);
device_set_desc(child, "MFI Logical Disk");
- mtx_unlock(&sc->mfi_io_lock);
- mtx_lock(&Giant);
bus_generic_attach(sc->mfi_dev);
mtx_unlock(&Giant);
mtx_lock(&sc->mfi_io_lock);
-
- return (0);
}
static struct mfi_command *
@@ -951,7 +1540,7 @@
struct mfi_io_frame *io;
struct mfi_command *cm;
struct bio *bio;
- int flags, blkcount;;
+ int flags, blkcount;
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (NULL);
@@ -993,7 +1582,6 @@
cm->cm_sg = &io->sgl;
cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
cm->cm_flags = flags;
-
return (cm);
}
@@ -1024,6 +1612,7 @@
mfi_startio(struct mfi_softc *sc)
{
struct mfi_command *cm;
+ struct ccb_hdr *ccbh;
for (;;) {
/* Don't bother if we're short on resources */
@@ -1033,6 +1622,11 @@
/* Try a command that has already been prepared */
cm = mfi_dequeue_ready(sc);
+ if (cm == NULL) {
+ if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
+ cm = sc->mfi_cam_start(ccbh);
+ }
+
/* Nope, so look for work on the bioq */
if (cm == NULL)
cm = mfi_bio_command(sc);
@@ -1054,6 +1648,8 @@
{
int error, polled;
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
if (cm->cm_data != NULL) {
polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
@@ -1063,7 +1659,6 @@
return (0);
}
} else {
- mfi_enqueue_busy(cm);
error = mfi_send_frame(sc, cm);
}
@@ -1079,14 +1674,18 @@
struct mfi_softc *sc;
int i, dir;
- if (error)
- return;
-
cm = (struct mfi_command *)arg;
sc = cm->cm_sc;
hdr = &cm->cm_frame->header;
sgl = cm->cm_sg;
+ if (error) {
+ printf("error %d in callback\n", error);
+ cm->cm_error = error;
+ mfi_complete(sc, cm);
+ return;
+ }
+
if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
for (i = 0; i < nsegs; i++) {
sgl->sg32[i].addr = segs[i].ds_addr;
@@ -1119,14 +1718,10 @@
* least 1 frame, so don't compensate for the modulo of the
* following division.
*/
- cm->cm_total_frame_size += (sc->mfi_sgsize * nsegs);
+ cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
- /* The caller will take care of delivering polled commands */
- if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
- mfi_enqueue_busy(cm);
- mfi_send_frame(sc, cm);
- }
+ mfi_send_frame(sc, cm);
return;
}
@@ -1134,22 +1729,53 @@
static int
mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
{
+ struct mfi_frame_header *hdr;
+ int tm = MFI_POLL_TIMEOUT_SECS * 1000;
+
+ hdr = &cm->cm_frame->header;
+
+ if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
+ cm->cm_timestamp = time_uptime;
+ mfi_enqueue_busy(cm);
+ } else {
+ hdr->cmd_status = 0xff;
+ hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+ }
/*
* The bus address of the command is aligned on a 64 byte boundary,
* leaving the least 6 bits as zero. For whatever reason, the
* hardware wants the address shifted right by three, leaving just
- * 3 zero bits. These three bits are then used to indicate how many
- * 64 byte frames beyond the first one are used in the command. The
- * extra frames are typically filled with S/G elements. The extra
- * frames must also be contiguous. Thus, a compound frame can be at
- * most 512 bytes long, allowing for up to 59 32-bit S/G elements or
- * 39 64-bit S/G elements for block I/O commands. This means that
- * I/O transfers of 256k and higher simply are not possible, which
- * is quite odd for such a modern adapter.
+ * 3 zero bits. These three bits are then used as a prefetching
+ * hint for the hardware to predict how many frames need to be
+ * fetched across the bus. If a command has more than 8 frames
+ * then the 3 bits are set to 0x7 and the firmware uses other
+ * information in the command to determine the total amount to fetch.
+ * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
+ * is enough for both 32bit and 64bit systems.
*/
- MFI_WRITE4(sc, MFI_IQP, (cm->cm_frame_busaddr >> 3) |
- cm->cm_extra_frames);
+ if (cm->cm_extra_frames > 7)
+ cm->cm_extra_frames = 7;
+
+ sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames);
+
+ if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
+ return (0);
+
+ /* This is a polled command, so busy-wait for it to complete. */
+ while (hdr->cmd_status == 0xff) {
+ DELAY(1000);
+ tm -= 1;
+ if (tm <= 0)
+ break;
+ }
+
+ if (hdr->cmd_status == 0xff) {
+ device_printf(sc->mfi_dev, "Frame %p timed out "
+ "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
+ return (ETIMEDOUT);
+ }
+
return (0);
}
@@ -1170,11 +1796,46 @@
cm->cm_flags &= ~MFI_CMD_MAPPED;
}
+ cm->cm_flags |= MFI_CMD_COMPLETED;
+
if (cm->cm_complete != NULL)
cm->cm_complete(cm);
+ else
+ wakeup(cm);
+}
- sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
- mfi_startio(sc);
+static int
+mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
+{
+ struct mfi_command *cm;
+ struct mfi_abort_frame *abort;
+ int i = 0;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
+ return (EBUSY);
+ }
+
+ abort = &cm->cm_frame->abort;
+ abort->header.cmd = MFI_CMD_ABORT;
+ abort->header.flags = 0;
+ abort->abort_context = cm_abort->cm_frame->header.context;
+ abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
+ abort->abort_mfi_addr_hi = 0;
+ cm->cm_data = NULL;
+ cm->cm_flags = MFI_CMD_POLLED;
+
+ sc->mfi_aen_cm->cm_aen_abort = 1;
+ mfi_mapcmd(sc, cm);
+ mfi_release_command(cm);
+
+ while (i < 5 && sc->mfi_aen_cm != NULL) {
+ msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
+ i++;
+ }
+
+ return (0);
}
int
@@ -1204,12 +1865,7 @@
cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
- if ((error = mfi_mapcmd(sc, cm)) != 0) {
- mfi_release_command(cm);
- return (error);
- }
-
- error = mfi_polled_command(sc, cm);
+ error = mfi_mapcmd(sc, cm);
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
@@ -1222,30 +1878,162 @@
mfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
{
struct mfi_softc *sc;
+ int error;
sc = dev->si_drv1;
- sc->mfi_flags |= MFI_FLAGS_OPEN;
- return (0);
+ mtx_lock(&sc->mfi_io_lock);
+ if (sc->mfi_detaching)
+ error = ENXIO;
+ else {
+ sc->mfi_flags |= MFI_FLAGS_OPEN;
+ error = 0;
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+
+ return (error);
}
static int
mfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
{
struct mfi_softc *sc;
+ struct mfi_aen *mfi_aen_entry, *tmp;
sc = dev->si_drv1;
+
+ mtx_lock(&sc->mfi_io_lock);
sc->mfi_flags &= ~MFI_FLAGS_OPEN;
+ TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
+ if (mfi_aen_entry->p == curproc) {
+ TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+ aen_link);
+ free(mfi_aen_entry, M_MFIBUF);
+ }
+ }
+ mtx_unlock(&sc->mfi_io_lock);
return (0);
}
static int
+mfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
+{
+
+ switch (opcode) {
+ case MFI_DCMD_LD_DELETE:
+ case MFI_DCMD_CFG_ADD:
+ case MFI_DCMD_CFG_CLEAR:
+ sx_xlock(&sc->mfi_config_lock);
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+static void
+mfi_config_unlock(struct mfi_softc *sc, int locked)
+{
+
+ if (locked)
+ sx_xunlock(&sc->mfi_config_lock);
+}
+
+/* Perform pre-issue checks on commands from userland and possibly veto them. */
+static int
+mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
+{
+ struct mfi_disk *ld, *ld2;
+ int error;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ error = 0;
+ switch (cm->cm_frame->dcmd.opcode) {
+ case MFI_DCMD_LD_DELETE:
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
+ break;
+ }
+ if (ld == NULL)
+ error = ENOENT;
+ else
+ error = mfi_disk_disable(ld);
+ break;
+ case MFI_DCMD_CFG_CLEAR:
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ error = mfi_disk_disable(ld);
+ if (error)
+ break;
+ }
+ if (error) {
+ TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
+ if (ld2 == ld)
+ break;
+ mfi_disk_enable(ld2);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/* Perform post-issue checks on commands from userland. */
+static void
+mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
+{
+ struct mfi_disk *ld, *ldn;
+
+ switch (cm->cm_frame->dcmd.opcode) {
+ case MFI_DCMD_LD_DELETE:
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
+ break;
+ }
+ KASSERT(ld != NULL, ("volume dissappeared"));
+ if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+ mtx_unlock(&sc->mfi_io_lock);
+ mtx_lock(&Giant);
+ device_delete_child(sc->mfi_dev, ld->ld_dev);
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+ } else
+ mfi_disk_enable(ld);
+ break;
+ case MFI_DCMD_CFG_CLEAR:
+ if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+ mtx_unlock(&sc->mfi_io_lock);
+ mtx_lock(&Giant);
+ TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
+ device_delete_child(sc->mfi_dev, ld->ld_dev);
+ }
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+ } else {
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
+ mfi_disk_enable(ld);
+ }
+ break;
+ case MFI_DCMD_CFG_ADD:
+ mfi_ldprobe(sc);
+ break;
+ }
+}
+
+static int
mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
{
struct mfi_softc *sc;
union mfi_statrequest *ms;
- int error;
+ struct mfi_ioc_packet *ioc;
+ struct mfi_ioc_aen *aen;
+ struct mfi_command *cm = NULL;
+ uint32_t context;
+ uint8_t *sense_ptr;
+ uint8_t *data = NULL, *temp;
+ int i;
+ int error, locked;
sc = dev->si_drv1;
error = 0;
@@ -1262,14 +2050,509 @@
sizeof(struct mfi_qstat));
break;
default:
- error = ENOENT;
+ error = ENOIOCTL;
break;
}
break;
+ case MFIIO_QUERY_DISK:
+ {
+ struct mfi_query_disk *qd;
+ struct mfi_disk *ld;
+
+ qd = (struct mfi_query_disk *)arg;
+ mtx_lock(&sc->mfi_io_lock);
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ if (ld->ld_id == qd->array_id)
+ break;
+ }
+ if (ld == NULL) {
+ qd->present = 0;
+ mtx_unlock(&sc->mfi_io_lock);
+ return (0);
+ }
+ qd->present = 1;
+ if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
+ qd->open = 1;
+ bzero(qd->devname, SPECNAMELEN + 1);
+ snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
+ mtx_unlock(&sc->mfi_io_lock);
+ break;
+ }
+ case MFI_CMD:
+ ioc = (struct mfi_ioc_packet *)arg;
+
+ mtx_lock(&sc->mfi_io_lock);
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (EBUSY);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+ locked = 0;
+
+ /*
+ * save off original context since copying from user
+ * will clobber some data
+ */
+ context = cm->cm_frame->header.context;
+
+ bcopy(ioc->mfi_frame.raw, cm->cm_frame,
+ 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
+ if (ioc->mfi_sge_count) {
+ cm->cm_sg =
+ (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
+ }
+ cm->cm_flags = 0;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+ cm->cm_flags |= MFI_CMD_DATAIN;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+ cm->cm_flags |= MFI_CMD_DATAOUT;
+ /* Legacy app shim */
+ if (cm->cm_flags == 0)
+ cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
+ cm->cm_len = cm->cm_frame->header.data_len;
+ if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+ M_WAITOK | M_ZERO);
+ if (cm->cm_data == NULL) {
+ device_printf(sc->mfi_dev, "Malloc failed\n");
+ goto out;
+ }
+ } else {
+ cm->cm_data = 0;
+ }
+
+ /* restore header context */
+ cm->cm_frame->header.context = context;
+
+ temp = data;
+ if (cm->cm_flags & MFI_CMD_DATAOUT) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyin(ioc->mfi_sgl[i].iov_base,
+ temp,
+ ioc->mfi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed\n");
+ goto out;
+ }
+ temp = &temp[ioc->mfi_sgl[i].iov_len];
+ }
+ }
+
+ if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
+ locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
+
+ mtx_lock(&sc->mfi_io_lock);
+ error = mfi_check_command_pre(sc, cm);
+ if (error) {
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
+
+ if ((error = mfi_wait_command(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev,
+ "Controller polled failed\n");
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
+
+ mfi_check_command_post(sc, cm);
+ mtx_unlock(&sc->mfi_io_lock);
+
+ temp = data;
+ if (cm->cm_flags & MFI_CMD_DATAIN) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyout(temp,
+ ioc->mfi_sgl[i].iov_base,
+ ioc->mfi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ temp = &temp[ioc->mfi_sgl[i].iov_len];
+ }
+ }
+
+ if (ioc->mfi_sense_len) {
+ /* copy out sense */
+ sense_ptr = &((struct mfi_ioc_packet*)arg)
+ ->mfi_frame.raw[0];
+ error = copyout(cm->cm_sense, sense_ptr,
+ ioc->mfi_sense_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ }
+
+ ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
+out:
+ mfi_config_unlock(sc, locked);
+ if (data)
+ free(data, M_MFIBUF);
+ if (cm) {
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ }
+
+ break;
+ case MFI_SET_AEN:
+ aen = (struct mfi_ioc_aen *)arg;
+ error = mfi_aen_register(sc, aen->aen_seq_num,
+ aen->aen_class_locale);
+
+ break;
+ case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
+ {
+ devclass_t devclass;
+ struct mfi_linux_ioc_packet l_ioc;
+ int adapter;
+
+ devclass = devclass_find("mfi");
+ if (devclass == NULL)
+ return (ENOENT);
+
+ error = copyin(arg, &l_ioc, sizeof(l_ioc));
+ if (error)
+ return (error);
+ adapter = l_ioc.lioc_adapter_no;
+ sc = devclass_get_softc(devclass, adapter);
+ if (sc == NULL)
+ return (ENOENT);
+ return (mfi_linux_ioctl_int(sc->mfi_cdev,
+ cmd, arg, flag, td));
+ break;
+ }
+ case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
+ {
+ devclass_t devclass;
+ struct mfi_linux_ioc_aen l_aen;
+ int adapter;
+
+ devclass = devclass_find("mfi");
+ if (devclass == NULL)
+ return (ENOENT);
+
+ error = copyin(arg, &l_aen, sizeof(l_aen));
+ if (error)
+ return (error);
+ adapter = l_aen.laen_adapter_no;
+ sc = devclass_get_softc(devclass, adapter);
+ if (sc == NULL)
+ return (ENOENT);
+ return (mfi_linux_ioctl_int(sc->mfi_cdev,
+ cmd, arg, flag, td));
+ break;
+ }
default:
+ device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
error = ENOENT;
break;
}
return (error);
}
+
+static int
+mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
+{
+ struct mfi_softc *sc;
+ struct mfi_linux_ioc_packet l_ioc;
+ struct mfi_linux_ioc_aen l_aen;
+ struct mfi_command *cm = NULL;
+ struct mfi_aen *mfi_aen_entry;
+ uint8_t *sense_ptr;
+ uint32_t context;
+ uint8_t *data = NULL, *temp;
+ void *temp_convert;
+ int i;
+ int error, locked;
+
+ sc = dev->si_drv1;
+ error = 0;
+ switch (cmd) {
+ case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
+ error = copyin(arg, &l_ioc, sizeof(l_ioc));
+ if (error != 0)
+ return (error);
+
+ if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
+ return (EINVAL);
+ }
+
+ mtx_lock(&sc->mfi_io_lock);
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (EBUSY);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+ locked = 0;
+
+ /*
+ * save off original context since copying from user
+ * will clobber some data
+ */
+ context = cm->cm_frame->header.context;
+
+ bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
+ 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
+ if (l_ioc.lioc_sge_count)
+ cm->cm_sg =
+ (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
+ cm->cm_flags = 0;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+ cm->cm_flags |= MFI_CMD_DATAIN;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+ cm->cm_flags |= MFI_CMD_DATAOUT;
+ cm->cm_len = cm->cm_frame->header.data_len;
+ if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+ M_WAITOK | M_ZERO);
+ if (cm->cm_data == NULL) {
+ device_printf(sc->mfi_dev, "Malloc failed\n");
+ goto out;
+ }
+ } else {
+ cm->cm_data = 0;
+ }
+
+ /* restore header context */
+ cm->cm_frame->header.context = context;
+
+ temp = data;
+ if (cm->cm_flags & MFI_CMD_DATAOUT) {
+ for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+ temp_convert =
+ (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+ error = copyin(temp_convert,
+ temp,
+ l_ioc.lioc_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed\n");
+ goto out;
+ }
+ temp = &temp[l_ioc.lioc_sgl[i].iov_len];
+ }
+ }
+
+ if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
+ locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
+
+ mtx_lock(&sc->mfi_io_lock);
+ error = mfi_check_command_pre(sc, cm);
+ if (error) {
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
+
+ if ((error = mfi_wait_command(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev,
+ "Controller polled failed\n");
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
+
+ mfi_check_command_post(sc, cm);
+ mtx_unlock(&sc->mfi_io_lock);
+
+ temp = data;
+ if (cm->cm_flags & MFI_CMD_DATAIN) {
+ for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+ temp_convert =
+ (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+ error = copyout(temp,
+ temp_convert,
+ l_ioc.lioc_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ temp = &temp[l_ioc.lioc_sgl[i].iov_len];
+ }
+ }
+
+ if (l_ioc.lioc_sense_len) {
+ /* copy out sense */
+ sense_ptr = &((struct mfi_linux_ioc_packet*)arg)
+ ->lioc_frame.raw[0];
+ error = copyout(cm->cm_sense, sense_ptr,
+ l_ioc.lioc_sense_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ }
+
+ error = copyout(&cm->cm_frame->header.cmd_status,
+ &((struct mfi_linux_ioc_packet*)arg)
+ ->lioc_frame.hdr.cmd_status,
+ 1);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+
+out:
+ mfi_config_unlock(sc, locked);
+ if (data)
+ free(data, M_MFIBUF);
+ if (cm) {
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ }
+
+ return (error);
+ case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
+ error = copyin(arg, &l_aen, sizeof(l_aen));
+ if (error != 0)
+ return (error);
+ printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
+ mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
+ M_WAITOK);
+ mtx_lock(&sc->mfi_io_lock);
+ if (mfi_aen_entry != NULL) {
+ mfi_aen_entry->p = curproc;
+ TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
+ aen_link);
+ }
+ error = mfi_aen_register(sc, l_aen.laen_seq_num,
+ l_aen.laen_class_locale);
+
+ if (error != 0) {
+ TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+ aen_link);
+ free(mfi_aen_entry, M_MFIBUF);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+
+ return (error);
+ default:
+ device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
+ error = ENOENT;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
+{
+ struct mfi_softc *sc;
+ int revents = 0;
+
+ sc = dev->si_drv1;
+
+ if (poll_events & (POLLIN | POLLRDNORM)) {
+ if (sc->mfi_aen_triggered != 0) {
+ revents |= poll_events & (POLLIN | POLLRDNORM);
+ sc->mfi_aen_triggered = 0;
+ }
+ if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
+ revents |= POLLERR;
+ }
+ }
+
+ if (revents == 0) {
+ if (poll_events & (POLLIN | POLLRDNORM)) {
+ sc->mfi_poll_waiting = 1;
+ selrecord(td, &sc->mfi_select);
+ }
+ }
+
+ return revents;
+}
+
+
+static void
+mfi_dump_all(void)
+{
+ struct mfi_softc *sc;
+ struct mfi_command *cm;
+ devclass_t dc;
+ time_t deadline;
+ int timedout;
+ int i;
+
+ dc = devclass_find("mfi");
+ if (dc == NULL) {
+ printf("No mfi dev class\n");
+ return;
+ }
+
+ for (i = 0; ; i++) {
+ sc = devclass_get_softc(dc, i);
+ if (sc == NULL)
+ break;
+ device_printf(sc->mfi_dev, "Dumping\n\n");
+ timedout = 0;
+ deadline = time_uptime - MFI_CMD_TIMEOUT;
+ mtx_lock(&sc->mfi_io_lock);
+ TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
+ if (cm->cm_timestamp < deadline) {
+ device_printf(sc->mfi_dev,
+ "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
+ (int)(time_uptime - cm->cm_timestamp));
+ MFI_PRINT_CMD(cm);
+ timedout++;
+ }
+ }
+
+#if 0
+ if (timedout)
+ MFI_DUMP_CMDS(SC);
+#endif
+
+ mtx_unlock(&sc->mfi_io_lock);
+ }
+
+ return;
+}
+
+static void
+mfi_timeout(void *data)
+{
+ struct mfi_softc *sc = (struct mfi_softc *)data;
+ struct mfi_command *cm;
+ time_t deadline;
+ int timedout = 0;
+
+ deadline = time_uptime - MFI_CMD_TIMEOUT;
+ mtx_lock(&sc->mfi_io_lock);
+ TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
+ if (sc->mfi_aen_cm == cm)
+ continue;
+ if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
+ device_printf(sc->mfi_dev,
+ "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
+ (int)(time_uptime - cm->cm_timestamp));
+ MFI_PRINT_CMD(cm);
+ MFI_VALIDATE_CMD(sc, cm);
+ timedout++;
+ }
+ }
+
+#if 0
+ if (timedout)
+ MFI_DUMP_CMDS(SC);
+#endif
+
+ mtx_unlock(&sc->mfi_io_lock);
+
+ callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+ mfi_timeout, sc);
+
+ if (0)
+ mfi_dump_all();
+ return;
+}
Index: mfi_ioctl.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_ioctl.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_ioctl.h -L sys/dev/mfi/mfi_ioctl.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_ioctl.h
+++ sys/dev/mfi/mfi_ioctl.h
@@ -25,8 +25,14 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_ioctl.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_ioctl.h,v 1.5 2007/05/10 15:33:41 scottl Exp $");
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+struct iovec32 {
+ u_int32_t iov_base;
+ int iov_len;
+};
+#endif
#define MFIQ_FREE 0
#define MFIQ_BIO 1
@@ -44,5 +50,78 @@
struct mfi_qstat ms_qstat;
};
+#define MAX_IOCTL_SGE 16
+
+struct mfi_ioc_packet {
+ uint16_t mfi_adapter_no;
+ uint16_t mfi_pad1;
+ uint32_t mfi_sgl_off;
+ uint32_t mfi_sge_count;
+ uint32_t mfi_sense_off;
+ uint32_t mfi_sense_len;
+ union {
+ uint8_t raw[128];
+ struct mfi_frame_header hdr;
+ } mfi_frame;
+
+ struct iovec mfi_sgl[MAX_IOCTL_SGE];
+} __packed;
+
+struct mfi_ioc_aen {
+ uint16_t aen_adapter_no;
+ uint16_t aen_pad1;
+ uint32_t aen_seq_num;
+ uint32_t aen_class_locale;
+} __packed;
+
+#define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet)
+#define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen)
+
+#define MAX_LINUX_IOCTL_SGE 16
+
+struct mfi_linux_ioc_packet {
+ uint16_t lioc_adapter_no;
+ uint16_t lioc_pad1;
+ uint32_t lioc_sgl_off;
+ uint32_t lioc_sge_count;
+ uint32_t lioc_sense_off;
+ uint32_t lioc_sense_len;
+ union {
+ uint8_t raw[128];
+ struct mfi_frame_header hdr;
+ } lioc_frame;
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+ struct iovec32 lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#else
+ struct iovec lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#endif
+} __packed;
+
#define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest)
+struct mfi_linux_ioc_aen {
+ uint16_t laen_adapter_no;
+ uint16_t laen_pad1;
+ uint32_t laen_seq_num;
+ uint32_t laen_class_locale;
+} __packed;
+
+struct mfi_query_disk {
+ uint8_t array_id;
+ uint8_t present;
+ uint8_t open;
+ uint8_t reserved; /* reserved for future use */
+ char devname[SPECNAMELEN + 1];
+} __packed;
+
+#define MFIIO_QUERY_DISK _IOWR('Q', 102, struct mfi_query_disk)
+
+/*
+ * Create a second set so the FreeBSD native ioctl doesn't
+ * conflict in FreeBSD ioctl handler. Translate in mfi_linux.c.
+ */
+#define MFI_LINUX_CMD 0xc1144d01
+#define MFI_LINUX_SET_AEN 0x400c4d03
+#define MFI_LINUX_CMD_2 0xc1144d02
+#define MFI_LINUX_SET_AEN_2 0x400c4d04
--- /dev/null
+++ sys/dev/mfi/mfi_cam.c
@@ -0,0 +1,386 @@
+/*-
+ * Copyright 2007 Scott Long
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.2.2.1 2007/10/19 15:23:23 scottl Exp $");
+
+#include "opt_mfi.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/selinfo.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/eventhandler.h>
+#include <sys/rman.h>
+#include <sys/bus_dma.h>
+#include <sys/bio.h>
+#include <sys/ioccom.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/md_var.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+struct mfip_softc {
+ device_t dev;
+ struct mfi_softc *mfi_sc;
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct cam_path *path;
+};
+
+static int mfip_probe(device_t);
+static int mfip_attach(device_t);
+static int mfip_detach(device_t);
+static void mfip_cam_action(struct cam_sim *, union ccb *);
+static void mfip_cam_poll(struct cam_sim *);
+static struct mfi_command * mfip_start(void *);
+static void mfip_done(struct mfi_command *cm);
+
+static devclass_t mfip_devclass;
+static device_method_t mfip_methods[] = {
+ DEVMETHOD(device_probe, mfip_probe),
+ DEVMETHOD(device_attach, mfip_attach),
+ DEVMETHOD(device_detach, mfip_detach),
+ {0, 0}
+};
+static driver_t mfip_driver = {
+ "mfip",
+ mfip_methods,
+ sizeof(struct mfip_softc)
+};
+DRIVER_MODULE(mfip, mfi, mfip_driver, mfip_devclass, 0, 0);
+MODULE_DEPEND(mfip, cam, 1, 1, 1);
+
+#define ccb_mfip_ptr sim_priv.entries[0].ptr
+
+static int
+mfip_probe(device_t dev)
+{
+
+ device_set_desc(dev, "SCSI Passthrough Bus");
+ return (0);
+}
+
+static int
+mfip_attach(device_t dev)
+{
+ struct mfip_softc *sc;
+ struct mfi_softc *mfisc;
+
+ sc = device_get_softc(dev);
+ if (sc == NULL)
+ return (EINVAL);
+
+ mfisc = device_get_softc(device_get_parent(dev));
+ sc->dev = dev;
+ sc->mfi_sc = mfisc;
+ mfisc->mfi_cam_start = mfip_start;
+
+ if ((sc->devq = cam_simq_alloc(MFI_SCSI_MAX_CMDS)) == NULL)
+ return (ENOMEM);
+
+ sc->sim = cam_sim_alloc(mfip_cam_action, mfip_cam_poll, "mfi", sc,
+ device_get_unit(dev), &mfisc->mfi_io_lock, 1,
+ MFI_SCSI_MAX_CMDS, sc->devq);
+ if (sc->sim == NULL) {
+ cam_simq_free(sc->devq);
+ device_printf(dev, "CAM SIM attach failed\n");
+ return (EINVAL);
+ }
+
+ mtx_lock(&mfisc->mfi_io_lock);
+ if (xpt_bus_register(sc->sim, dev, 0) != 0) {
+ device_printf(dev, "XPT bus registration failed\n");
+ cam_sim_free(sc->sim, FALSE);
+ cam_simq_free(sc->devq);
+ mtx_unlock(&mfisc->mfi_io_lock);
+ return (EINVAL);
+ }
+ mtx_unlock(&mfisc->mfi_io_lock);
+
+ return (0);
+}
+
+static int
+mfip_detach(device_t dev)
+{
+ struct mfip_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc == NULL)
+ return (EINVAL);
+
+ if (sc->sim != NULL) {
+ mtx_lock(&sc->mfi_sc->mfi_io_lock);
+ xpt_bus_deregister(cam_sim_path(sc->sim));
+ cam_sim_free(sc->sim, FALSE);
+ mtx_unlock(&sc->mfi_sc->mfi_io_lock);
+ }
+
+ if (sc->devq != NULL)
+ cam_simq_free(sc->devq);
+
+ return (0);
+}
+
+static void
+mfip_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct mfip_softc *sc = cam_sim_softc(sim);
+ struct mfi_softc *mfisc = sc->mfi_sc;
+
+ mtx_assert(&mfisc->mfi_io_lock, MA_OWNED);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1;
+ 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 = MFI_SCSI_MAX_TARGETS;
+ cpi->max_lun = MFI_SCSI_MAX_LUNS;
+ cpi->initiator_id = MFI_SCSI_INITIATOR_ID;
+ 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 = 150000;
+ cpi->transport = XPORT_SAS;
+ cpi->transport_version = 0;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_2;
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_RESET_BUS:
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_RESET_DEV:
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings_sas *sas =
+ &ccb->cts.xport_specific.sas;
+
+ ccb->cts.protocol = PROTO_SCSI;
+ ccb->cts.protocol_version = SCSI_REV_2;
+ ccb->cts.transport = XPORT_SAS;
+ ccb->cts.transport_version = 0;
+
+ sas->valid &= ~CTS_SAS_VALID_SPEED;
+ sas->bitrate = 150000;
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ break;
+ case XPT_SCSI_IO:
+ {
+ struct ccb_hdr *ccbh = &ccb->ccb_h;
+ struct ccb_scsiio *csio = &ccb->csio;
+
+ ccbh->status = CAM_REQ_INPROG;
+ if (csio->cdb_len > MFI_SCSI_MAX_CDB_LEN) {
+ ccbh->status = CAM_REQ_INVALID;
+ break;
+ }
+ if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if (ccbh->flags & CAM_DATA_PHYS) {
+ ccbh->status = CAM_REQ_INVALID;
+ break;
+ }
+ if (ccbh->flags & CAM_SCATTER_VALID) {
+ ccbh->status = CAM_REQ_INVALID;
+ break;
+ }
+ }
+
+ ccbh->ccb_mfip_ptr = sc;
+ TAILQ_INSERT_TAIL(&mfisc->mfi_cam_ccbq, ccbh, sim_links.tqe);
+ mfi_startio(mfisc);
+ return;
+ }
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+
+ xpt_done(ccb);
+ return;
+}
+
+static struct mfi_command *
+mfip_start(void *data)
+{
+ union ccb *ccb = data;
+ struct ccb_hdr *ccbh = &ccb->ccb_h;
+ struct ccb_scsiio *csio = &ccb->csio;
+ struct mfip_softc *sc;
+ struct mfi_pass_frame *pt;
+ struct mfi_command *cm;
+
+ sc = ccbh->ccb_mfip_ptr;
+
+ if ((cm = mfi_dequeue_free(sc->mfi_sc)) == NULL)
+ return (NULL);
+
+ pt = &cm->cm_frame->pass;
+ pt->header.cmd = MFI_CMD_PD_SCSI_IO;
+ pt->header.cmd_status = 0;
+ pt->header.scsi_status = 0;
+ pt->header.target_id = ccbh->target_id;
+ pt->header.lun_id = ccbh->target_lun;
+ pt->header.flags = 0;
+ pt->header.timeout = 0;
+ pt->header.data_len = csio->dxfer_len;
+ pt->header.sense_len = MFI_SENSE_LEN;
+ pt->header.cdb_len = csio->cdb_len;
+ pt->sense_addr_lo = cm->cm_sense_busaddr;
+ pt->sense_addr_hi = 0;
+ if (ccbh->flags & CAM_CDB_POINTER)
+ bcopy(csio->cdb_io.cdb_ptr, &pt->cdb[0], csio->cdb_len);
+ else
+ bcopy(csio->cdb_io.cdb_bytes, &pt->cdb[0], csio->cdb_len);
+ cm->cm_complete = mfip_done;
+ cm->cm_private = ccb;
+ cm->cm_sg = &pt->sgl;
+ cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+ cm->cm_data = csio->data_ptr;
+ cm->cm_len = csio->dxfer_len;
+ switch (ccbh->flags & CAM_DIR_MASK) {
+ case CAM_DIR_IN:
+ cm->cm_flags = MFI_CMD_DATAIN;
+ break;
+ case CAM_DIR_OUT:
+ cm->cm_flags = MFI_CMD_DATAOUT;
+ break;
+ case CAM_DIR_NONE:
+ default:
+ cm->cm_data = NULL;
+ cm->cm_len = 0;
+ cm->cm_flags = 0;
+ break;
+ }
+
+ TAILQ_REMOVE(&sc->mfi_sc->mfi_cam_ccbq, ccbh, sim_links.tqe);
+ return (cm);
+}
+
+static void
+mfip_done(struct mfi_command *cm)
+{
+ union ccb *ccb = cm->cm_private;
+ struct ccb_hdr *ccbh = &ccb->ccb_h;
+ struct ccb_scsiio *csio = &ccb->csio;
+ struct mfip_softc *sc;
+ struct mfi_pass_frame *pt;
+
+ sc = ccbh->ccb_mfip_ptr;
+ pt = &cm->cm_frame->pass;
+
+ switch (pt->header.cmd_status) {
+ case MFI_STAT_OK:
+ {
+ uint8_t command, device;
+
+ ccbh->status = CAM_REQ_CMP;
+ csio->scsi_status = pt->header.scsi_status;
+ if (ccbh->flags & CAM_CDB_POINTER)
+ command = ccb->csio.cdb_io.cdb_ptr[0];
+ else
+ command = ccb->csio.cdb_io.cdb_bytes[0];
+ if (command == INQUIRY) {
+ device = ccb->csio.data_ptr[0] & 0x1f;
+ if ((device == T_DIRECT) || (device == T_PROCESSOR))
+ csio->data_ptr[0] =
+ (device & 0xe0) | T_NODEVICE;
+ }
+ break;
+ }
+ case MFI_STAT_SCSI_DONE_WITH_ERROR:
+ {
+ int sense_len;
+
+ ccbh->status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
+ csio->scsi_status = pt->header.scsi_status;
+ sense_len = min(pt->header.sense_len, sizeof(struct scsi_sense_data));
+ bzero(&csio->sense_data, sizeof(struct scsi_sense_data));
+ bcopy(&cm->cm_sense->data[0], &csio->sense_data, sense_len);
+ break;
+ }
+ case MFI_STAT_DEVICE_NOT_FOUND:
+ ccbh->status = CAM_SEL_TIMEOUT;
+ break;
+ case MFI_STAT_SCSI_IO_FAILED:
+ ccbh->status = CAM_REQ_CMP_ERR;
+ csio->scsi_status = pt->header.scsi_status;
+ break;
+ default:
+ ccbh->status = CAM_REQ_CMP_ERR;
+ csio->scsi_status = pt->header.scsi_status;
+ break;
+ }
+
+ mfi_release_command(cm);
+ xpt_done(ccb);
+}
+
+static void
+mfip_cam_poll(struct cam_sim *sim)
+{
+ return;
+}
+
Index: mfi_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_pci.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_pci.c -L sys/dev/mfi/mfi_pci.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_pci.c
+++ sys/dev/mfi/mfi_pci.c
@@ -23,10 +23,35 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.9 2007/08/25 23:58:45 scottl Exp $");
/* PCI/PCI-X/PCIe bus interface for the LSI MegaSAS controllers */
@@ -35,11 +60,13 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/selinfo.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/malloc.h>
+#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -87,8 +114,10 @@
int flags;
const char *desc;
} mfi_identifiers[] = {
- {0x1000, 0x0411, 0xffff, 0xffff, 0, "LSI MegaSAS 1064R"},
- {0x1028, 0x0015, 0xffff, 0xffff, 0, "Dell PERC 5/i"},
+ {0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Brocton IOP */
+ {0x1000, 0x0413, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Verde ZCR */
+ {0x1028, 0x0015, 0xffff, 0xffff, MFI_FLAGS_1064R, "Dell PERC 5/i"},
+ {0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"},
{0, 0, 0, 0, 0, NULL}
};
@@ -193,21 +222,29 @@
mfi_pci_detach(device_t dev)
{
struct mfi_softc *sc;
- struct mfi_ld *ld;
+ struct mfi_disk *ld;
int error;
sc = device_get_softc(dev);
- if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0)
+ sx_xlock(&sc->mfi_config_lock);
+ mtx_lock(&sc->mfi_io_lock);
+ if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0) {
+ mtx_unlock(&sc->mfi_io_lock);
+ sx_xunlock(&sc->mfi_config_lock);
return (EBUSY);
+ }
+ sc->mfi_detaching = 1;
+ mtx_unlock(&sc->mfi_io_lock);
- while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
- error = device_delete_child(dev, ld->ld_disk);
- if (error)
+ while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
+ if ((error = device_delete_child(dev, ld->ld_dev)) != 0) {
+ sc->mfi_detaching = 0;
+ sx_xunlock(&sc->mfi_config_lock);
return (error);
- TAILQ_REMOVE(&sc->mfi_ld_tqh, ld, ld_link);
- free(ld, M_MFIBUF);
+ }
}
+ sx_xunlock(&sc->mfi_config_lock);
EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);
Index: mfireg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfireg.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfireg.h -L sys/dev/mfi/mfireg.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfireg.h
+++ sys/dev/mfi/mfireg.h
@@ -23,13 +23,38 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
#ifndef _MFIREG_H
#define _MFIREG_H
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.10.4.1 2008/02/04 14:54:21 ambrisko Exp $");
/*
* MegaRAID SAS MFI firmware definitions
@@ -57,6 +82,17 @@
#define MFI_IQP 0x40 /* Inbound queue port */
#define MFI_OQP 0x44 /* Outbound queue port */
+/*
+ * 1078 specific related register
+ */
+#define MFI_ODR0 0x9c /* outbound doorbell register0 */
+#define MFI_ODCR0 0xa0 /* outbound doorbell clear register0 */
+#define MFI_OSP0 0xb0 /* outbound scratch pad0 */
+#define MFI_1078_EIM 0x80000004 /* 1078 enable intrrupt mask */
+#define MFI_RMI 0x2 /* reply message interrupt */
+#define MFI_1078_RM 0x80000000 /* reply 1078 message interrupt */
+#define MFI_ODC 0x4 /* outbound doorbell change interrupt */
+
/* Bits for MFI_OSTS */
#define MFI_OSTS_INTR_VALID 0x00000002
@@ -102,12 +138,21 @@
/* Direct commands */
typedef enum {
MFI_DCMD_CTRL_GETINFO = 0x01010000,
+ MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
+ MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
MFI_DCMD_CTRL_FLUSHCACHE = 0x01101000,
MFI_DCMD_CTRL_SHUTDOWN = 0x01050000,
MFI_DCMD_CTRL_EVENT_GETINFO = 0x01040100,
MFI_DCMD_CTRL_EVENT_GET = 0x01040300,
MFI_DCMD_CTRL_EVENT_WAIT = 0x01040500,
+ MFI_DCMD_LD_GET_LIST = 0x03010000,
+ MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000,
+ MFI_DCMD_LD_SET_PROP = 0x03040000,
+ MFI_DCMD_LD_DELETE = 0x03090000,
+ MFI_DCMD_CFG_READ = 0x04010000,
+ MFI_DCMD_CFG_ADD = 0x04020000,
+ MFI_DCMD_CFG_CLEAR = 0x04030000,
MFI_DCMD_CLUSTER = 0x08000000,
MFI_DCMD_CLUSTER_RESET_ALL = 0x08010100,
MFI_DCMD_CLUSTER_RESET_LD = 0x08010200
@@ -121,7 +166,7 @@
#define MFI_SHUTDOWN_SPINDOWN 0x01
/*
- * MFI Frmae flags
+ * MFI Frame flags
*/
#define MFI_FRAME_POST_IN_REPLY_QUEUE 0x0000
#define MFI_FRAME_DONT_POST_IN_REPLY_QUEUE 0x0001
@@ -219,29 +264,45 @@
} mfi_evt_locale_t;
typedef enum {
- MR_EVT_ARGS_NONE = 0x00,
- MR_EVT_ARGS_CDB_SENSE,
- MR_EVT_ARGS_LD,
- MR_EVT_ARGS_LD_COUNT,
- MR_EVT_ARGS_LD_LBA,
- MR_EVT_ARGS_LD_OWNER,
- MR_EVT_ARGS_LD_LBA_PD_LBA,
- MR_EVT_ARGS_LD_PROG,
- MR_EVT_ARGS_LD_STATE,
- MR_EVT_ARGS_LD_STRIP,
- MR_EVT_ARGS_PD,
- MR_EVT_ARGS_PD_ERR,
- MR_EVT_ARGS_PD_LBA,
- MR_EVT_ARGS_PD_LBA_LD,
- MR_EVT_ARGS_PD_PROG,
- MR_EVT_ARGS_PD_STATE,
- MR_EVT_ARGS_PCI,
- MR_EVT_ARGS_RATE,
- MR_EVT_ARGS_STR,
- MR_EVT_ARGS_TIME,
- MR_EVT_ARGS_ECC
+ MR_EVT_ARGS_NONE = 0x00,
+ MR_EVT_ARGS_CDB_SENSE,
+ MR_EVT_ARGS_LD,
+ MR_EVT_ARGS_LD_COUNT,
+ MR_EVT_ARGS_LD_LBA,
+ MR_EVT_ARGS_LD_OWNER,
+ MR_EVT_ARGS_LD_LBA_PD_LBA,
+ MR_EVT_ARGS_LD_PROG,
+ MR_EVT_ARGS_LD_STATE,
+ MR_EVT_ARGS_LD_STRIP,
+ MR_EVT_ARGS_PD,
+ MR_EVT_ARGS_PD_ERR,
+ MR_EVT_ARGS_PD_LBA,
+ MR_EVT_ARGS_PD_LBA_LD,
+ MR_EVT_ARGS_PD_PROG,
+ MR_EVT_ARGS_PD_STATE,
+ MR_EVT_ARGS_PCI,
+ MR_EVT_ARGS_RATE,
+ MR_EVT_ARGS_STR,
+ MR_EVT_ARGS_TIME,
+ MR_EVT_ARGS_ECC
} mfi_evt_args;
+typedef enum {
+ MR_LD_CACHE_WRITE_BACK = 0x01,
+ MR_LD_CACHE_WRITE_ADAPTIVE = 0x02,
+ MR_LD_CACHE_READ_AHEAD = 0x04,
+ MR_LD_CACHE_READ_ADAPTIVE = 0x08,
+ MR_LD_CACHE_WRITE_CACHE_BAD_BBU=0x10,
+ MR_LD_CACHE_ALLOW_WRITE_CACHE = 0x20,
+ MR_LD_CACHE_ALLOW_READ_CACHE = 0x40
+} mfi_ld_cache;
+
+typedef enum {
+ MR_PD_CACHE_UNCHANGED = 0,
+ MR_PD_CACHE_ENABLE = 1,
+ MR_PD_CACHE_DISABLE = 2
+} mfi_pd_cache;
+
/*
* Other propertities and definitions
*/
@@ -256,7 +317,8 @@
#define MFI_FRAME_SIZE 64
#define MFI_MBOX_SIZE 12
-#define MFI_POLL_TIMEOUT_SECS 10
+/* Firmware flashing can take 40s */
+#define MFI_POLL_TIMEOUT_SECS 50
/* Allow for speedier math calculations */
#define MFI_SECTOR_LEN 512
@@ -290,6 +352,8 @@
uint32_t context;
uint32_t pad0;
uint16_t flags;
+#define MFI_FRAME_DATAOUT 0x08
+#define MFI_FRAME_DATAIN 0x10
uint16_t timeout;
uint32_t data_len;
} __packed;
@@ -454,6 +518,51 @@
char build_time[16];
} __packed;
+/* Controller default settings */
+struct mfi_defaults {
+ uint64_t sas_addr;
+ uint8_t phy_polarity;
+ uint8_t background_rate;
+ uint8_t stripe_size;
+ uint8_t flush_time;
+ uint8_t write_back;
+ uint8_t read_ahead;
+ uint8_t cache_when_bbu_bad;
+ uint8_t cached_io;
+ uint8_t smart_mode;
+ uint8_t alarm_disable;
+ uint8_t coercion;
+ uint8_t zrc_config;
+ uint8_t dirty_led_shows_drive_activity;
+ uint8_t bios_continue_on_error;
+ uint8_t spindown_mode;
+ uint8_t allowed_device_types;
+ uint8_t allow_mix_in_enclosure;
+ uint8_t allow_mix_in_ld;
+ uint8_t allow_sata_in_cluster;
+ uint8_t max_chained_enclosures;
+ uint8_t disable_ctrl_r;
+ uint8_t enabel_web_bios;
+ uint8_t phy_polarity_split;
+ uint8_t direct_pd_mapping;
+ uint8_t bios_enumerate_lds;
+ uint8_t restored_hot_spare_on_insertion;
+ uint8_t expose_enclosure_devices;
+ uint8_t maintain_pd_fail_history;
+ uint8_t resv[28];
+} __packed;
+
+/* Controller default settings */
+struct mfi_bios_data {
+ uint16_t boot_target_id;
+ uint8_t do_not_int_13;
+ uint8_t continue_on_error;
+ uint8_t verbose;
+ uint8_t geometry;
+ uint8_t expose_all_drives;
+ uint8_t reserved[56];
+ uint8_t check_sum;
+} __packed;
/* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
struct mfi_ctrl_info {
@@ -509,7 +618,7 @@
#define MFI_INFO_RAID_6 0x10
uint32_t adapter_ops;
-#define MFI_INFO_AOPS_RBLD_RATE 0x0001
+#define MFI_INFO_AOPS_RBLD_RATE 0x0001
#define MFI_INFO_AOPS_CC_RATE 0x0002
#define MFI_INFO_AOPS_BGI_RATE 0x0004
#define MFI_INFO_AOPS_RECON_RATE 0x0008
@@ -557,4 +666,418 @@
uint8_t pad[0x800 - 0x6a0];
} __packed;
+/* keep track of an event. */
+union mfi_evt {
+ struct {
+ uint16_t locale;
+ uint8_t reserved;
+ int8_t class;
+ } members;
+ uint32_t word;
+} __packed;
+
+/* event log state. */
+struct mfi_evt_log_state {
+ uint32_t newest_seq_num;
+ uint32_t oldest_seq_num;
+ uint32_t clear_seq_num;
+ uint32_t shutdown_seq_num;
+ uint32_t boot_seq_num;
+} __packed;
+
+struct mfi_progress {
+ uint16_t progress;
+ uint16_t elapsed_seconds;
+} __packed;
+
+struct mfi_evt_ld {
+ uint16_t target_id;
+ uint8_t ld_index;
+ uint8_t reserved;
+} __packed;
+
+struct mfi_evt_pd {
+ uint16_t device_id;
+ uint8_t enclosure_index;
+ uint8_t slot_number;
+} __packed;
+
+/* SAS (?) event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
+struct mfi_evt_detail {
+ uint32_t seq;
+ uint32_t time;
+ uint32_t code;
+ union mfi_evt class;
+ uint8_t arg_type;
+ uint8_t reserved1[15];
+
+ union {
+ struct {
+ struct mfi_evt_pd pd;
+ uint8_t cdb_len;
+ uint8_t sense_len;
+ uint8_t reserved[2];
+ uint8_t cdb[16];
+ uint8_t sense[64];
+ } cdb_sense;
+
+ struct mfi_evt_ld ld;
+
+ struct {
+ struct mfi_evt_ld ld;
+ uint64_t count;
+ } ld_count;
+
+ struct {
+ uint64_t lba;
+ struct mfi_evt_ld ld;
+ } ld_lba;
+
+ struct {
+ struct mfi_evt_ld ld;
+ uint32_t pre_owner;
+ uint32_t new_owner;
+ } ld_owner;
+
+ struct {
+ uint64_t ld_lba;
+ uint64_t pd_lba;
+ struct mfi_evt_ld ld;
+ struct mfi_evt_pd pd;
+ } ld_lba_pd_lba;
+
+ struct {
+ struct mfi_evt_ld ld;
+ struct mfi_progress prog;
+ } ld_prog;
+
+ struct {
+ struct mfi_evt_ld ld;
+ uint32_t prev_state;
+ uint32_t new_state;
+ } ld_state;
+
+ struct {
+ uint64_t strip;
+ struct mfi_evt_ld ld;
+ } ld_strip;
+
+ struct mfi_evt_pd pd;
+
+ struct {
+ struct mfi_evt_pd pd;
+ uint32_t err;
+ } pd_err;
+
+ struct {
+ uint64_t lba;
+ struct mfi_evt_pd pd;
+ } pd_lba;
+
+ struct {
+ uint64_t lba;
+ struct mfi_evt_pd pd;
+ struct mfi_evt_ld ld;
+ } pd_lba_ld;
+
+ struct {
+ struct mfi_evt_pd pd;
+ struct mfi_progress prog;
+ } pd_prog;
+
+ struct {
+ struct mfi_evt_pd ld;
+ uint32_t prev_state;
+ uint32_t new_state;
+ } pd_state;
+
+ struct {
+ uint16_t venderId;
+ uint16_t deviceId;
+ uint16_t subVenderId;
+ uint16_t subDeviceId;
+ } pci;
+
+ uint32_t rate;
+
+ char str[96];
+
+ struct {
+ uint32_t rtc;
+ uint16_t elapsedSeconds;
+ } time;
+
+ struct {
+ uint32_t ecar;
+ uint32_t elog;
+ char str[64];
+ } ecc;
+
+ uint8_t b[96];
+ uint16_t s[48];
+ uint32_t w[24];
+ uint64_t d[12];
+ } args;
+
+ char description[128];
+} __packed;
+
+struct mfi_evt_list {
+ uint32_t count;
+ uint32_t reserved;
+ struct mfi_evt_detail event[1];
+} __packed;
+
+union mfi_pd_ref {
+ struct {
+ uint16_t device_id;
+ uint16_t seq_num;
+ } v;
+ uint32_t ref;
+} __packed;
+
+union mfi_pd_ddf_type {
+ struct {
+ union {
+ struct {
+ uint16_t forced_pd_guid : 1;
+ uint16_t in_vd : 1;
+ uint16_t is_global_spare : 1;
+ uint16_t is_spare : 1;
+ uint16_t is_foreign : 1;
+ uint16_t reserved : 7;
+ uint16_t intf : 4;
+ } pd_type;
+ uint16_t type;
+ } v;
+ uint16_t reserved;
+ } ddf;
+ struct {
+ uint32_t reserved;
+ } non_disk;
+ uint32_t type;
+} __packed;
+
+struct mfi_pd_progress {
+ struct {
+ uint32_t rbld : 1;
+ uint32_t patrol : 1;
+ uint32_t clear : 1;
+ uint32_t reserved: 29;
+ } active;
+ struct mfi_progress rbld;
+ struct mfi_progress patrol;
+ struct mfi_progress clear;
+ struct mfi_progress reserved[4];
+} __packed;
+
+struct mfi_pd_info {
+ union mfi_pd_ref ref;
+ uint8_t inquiry_data[96];
+ uint8_t vpd_page83[64];
+ uint8_t not_supported;
+ uint8_t scsi_dev_type;
+ uint8_t connected_port_bitmap;
+ uint8_t device_speed;
+ uint32_t media_err_count;
+ uint32_t other_err_count;
+ uint32_t pred_fail_count;
+ uint32_t last_pred_fail_event_seq_num;
+ uint16_t fw_state;
+ uint8_t disable_for_removal;
+ uint8_t link_speed;
+ union mfi_pd_ddf_type state;
+ struct {
+ uint8_t count;
+ uint8_t is_path_broken;
+ uint8_t reserved[6];
+ uint64_t sas_addr[4];
+ } path_info;
+ uint64_t raw_size;
+ uint64_t non_coerced_size;
+ uint64_t coerced_size;
+ uint16_t encl_device_id;
+ uint8_t encl_index;
+ uint8_t slot_number;
+ struct mfi_pd_progress prog_info;
+ uint8_t bad_block_table_full;
+ uint8_t unusable_in_current_config;
+ uint8_t vpd_page83_ext[64];
+ uint8_t reserved[512-358];
+} __packed;
+
+struct mfi_pd_address {
+ uint16_t device_id;
+ uint16_t encl_device_id;
+ uint8_t encl_index;
+ uint8_t slot_number;
+ uint8_t scsi_dev_type;
+ uint8_t connect_port_bitmap;
+ uint64_t sas_addr[2];
+} __packed;
+
+struct mfi_pd_list {
+ uint32_t size;
+ uint32_t count;
+ uint8_t data;
+ /*
+ struct mfi_pd_address addr[];
+ */
+} __packed;
+
+union mfi_ld_ref {
+ struct {
+ uint8_t target_id;
+ uint8_t reserved;
+ uint16_t seq;
+ } v;
+ uint32_t ref;
+} __packed;
+
+struct mfi_ld_list {
+ uint32_t ld_count;
+ uint32_t reserved1;
+ struct {
+ union mfi_ld_ref ld;
+ uint8_t state;
+ uint8_t reserved2[3];
+ uint64_t size;
+ } ld_list[MFI_MAX_LD];
+} __packed;
+
+enum mfi_ld_access {
+ MFI_LD_ACCESS_RW = 0,
+ MFI_LD_ACCSSS_RO = 2,
+ MFI_LD_ACCESS_BLOCKED = 3,
+};
+#define MFI_LD_ACCESS_MASK 3
+
+enum mfi_ld_state {
+ MFI_LD_STATE_OFFLINE = 0,
+ MFI_LD_STATE_PARTIALLY_DEGRADED = 1,
+ MFI_LD_STATE_DEGRADED = 2,
+ MFI_LD_STATE_OPTIMAL = 3
+};
+
+struct mfi_ld_props {
+ union mfi_ld_ref ld;
+ char name[16];
+ uint8_t default_cache_policy;
+ uint8_t access_policy;
+ uint8_t disk_cache_policy;
+ uint8_t current_cache_policy;
+ uint8_t no_bgi;
+ uint8_t reserved[7];
+} __packed;
+
+struct mfi_ld_params {
+ uint8_t primary_raid_level;
+ uint8_t raid_level_qualifier;
+ uint8_t secondary_raid_level;
+ uint8_t stripe_size;
+ uint8_t num_drives;
+ uint8_t span_depth;
+ uint8_t state;
+ uint8_t init_state;
+ uint8_t is_consistent;
+ uint8_t reserved[23];
+} __packed;
+
+struct mfi_ld_progress {
+ uint32_t active;
+#define MFI_LD_PROGRESS_CC (1<<0)
+#define MFI_LD_PROGRESS_BGI (1<<1)
+#define MFI_LD_PROGRESS_FGI (1<<2)
+#define MFI_LD_PORGRESS_RECON (1<<3)
+ struct mfi_progress cc;
+ struct mfi_progress bgi;
+ struct mfi_progress fgi;
+ struct mfi_progress recon;
+ struct mfi_progress reserved[4];
+} __packed;
+
+struct mfi_span {
+ uint64_t start_block;
+ uint64_t num_blocks;
+ uint16_t array_ref;
+ uint8_t reserved[6];
+} __packed;
+
+#define MFI_MAX_SPAN_DEPTH 8
+struct mfi_ld_config {
+ struct mfi_ld_props properties;
+ struct mfi_ld_params params;
+ struct mfi_span span[MFI_MAX_SPAN_DEPTH];
+} __packed;
+
+struct mfi_ld_info {
+ struct mfi_ld_config ld_config;
+ uint64_t size;
+ struct mfi_ld_progress progress;
+ uint16_t cluster_owner;
+ uint8_t reconstruct_active;
+ uint8_t reserved1[1];
+ uint8_t vpd_page83[64];
+ uint8_t reserved2[16];
+} __packed;
+
+union mfi_spare_type {
+ struct {
+ uint8_t is_dedicate :1;
+ uint8_t is_revertable :1;
+ uint8_t is_encl_affinity :1;
+ uint8_t reserved :5;
+ } v;
+ uint8_t type;
+} __packed;
+
+#define MAX_ARRAYS 16
+struct mfi_spare {
+ union mfi_pd_ref ref;
+ union mfi_spare_type spare_type;
+ uint8_t reserved[2];
+ uint8_t array_count;
+ uint16_t array_refd[MAX_ARRAYS];
+} __packed;
+
+#define MAX_ROW_SIZE 32
+struct mfi_array {
+ uint64_t size;
+ uint8_t num_drives;
+ uint8_t reserved;
+ uint16_t array_ref;
+ uint8_t pad[20];
+ struct {
+ union mfi_pd_ref ref;
+ uint16_t fw_state;
+ struct {
+ uint8_t pd;
+ uint8_t slot;
+ } encl;
+ } pd[MAX_ROW_SIZE];
+} __packed;
+
+struct mfi_config_data {
+ uint32_t size;
+ uint16_t array_count;
+ uint16_t array_size;
+ uint16_t log_drv_count;
+ uint16_t log_drv_size;
+ uint16_t spares_count;
+ uint16_t spares_size;
+ uint8_t reserved[16];
+ uint8_t data;
+ /*
+ struct mfi_array array[];
+ struct mfi_ld_config ld[];
+ struct mfi_spare spare[];
+ */
+} __packed;
+
+#define MFI_SCSI_MAX_TARGETS 128
+#define MFI_SCSI_MAX_LUNS 8
+#define MFI_SCSI_INITIATOR_ID 255
+#define MFI_SCSI_MAX_CMDS 8
+#define MFI_SCSI_MAX_CDB_LEN 16
+
#endif /* _MFIREG_H */
--- /dev/null
+++ sys/dev/mfi/mfi_debug.c
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_debug.c,v 1.3 2006/10/16 04:18:38 scottl Exp $");
+
+#include "opt_mfi.h"
+
+#ifdef MFI_DEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/selinfo.h>
+#include <sys/taskqueue.h>
+#include <sys/uio.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+static void
+mfi_print_frame_flags(device_t dev, uint32_t flags)
+{
+ device_printf(dev, "flags=%b\n", flags,
+ "\20"
+ "\1NOPOST"
+ "\2SGL64"
+ "\3SENSE64"
+ "\4WRITE"
+ "\5READ");
+}
+
+static void
+mfi_print_sgl(struct mfi_frame_header *hdr, union mfi_sgl *sgl, int count)
+{
+ int i, columns = 0;
+
+ printf("SG List:\n");
+ for (i = 0; i < count; i++) {
+ if (hdr->flags & MFI_FRAME_SGL64) {
+ printf("0x%lx:%06d ", (u_long)sgl->sg64[i].addr,
+ sgl->sg64[i].len);
+ columns += 26;
+ if (columns > 77) {
+ printf("\n");
+ columns = 0;
+ }
+ } else {
+ printf("0x%x:%06d ", sgl->sg32[i].addr,
+ sgl->sg32[i].len);
+ columns += 18;
+ if (columns > 71) {
+ printf("\n");
+ columns = 0;
+ }
+ }
+ }
+ if (columns != 0)
+ printf("\n");
+
+}
+
+static void
+mfi_print_ldio(struct mfi_softc *sc, device_t dev, struct mfi_command *cm)
+{
+ struct mfi_io_frame *io;
+ struct mfi_frame_header *hdr;
+
+ io = &cm->cm_frame->io;
+ hdr = &io->header;
+
+ device_printf(dev, "cmd=%s target_id=%d sg_count=%d data_len=%d "
+ "lba=%d\n", (hdr->cmd == MFI_CMD_LD_READ) ? "LD_READ":"LD_WRITE",
+ hdr->target_id, hdr->sg_count, hdr->data_len, io->lba_lo);
+ mfi_print_frame_flags(dev, hdr->flags);
+ mfi_print_sgl(hdr, &io->sgl, hdr->sg_count);
+
+}
+
+static void
+mfi_print_dcmd(struct mfi_softc *sc, device_t dev, struct mfi_command *cm)
+{
+ struct mfi_dcmd_frame *dcmd;
+ struct mfi_frame_header *hdr;
+ const char *opcode;
+
+ dcmd = &cm->cm_frame->dcmd;
+ hdr = &dcmd->header;
+
+ switch (dcmd->opcode) {
+ case MFI_DCMD_CTRL_GETINFO:
+ opcode = "CTRL_GETINFO";
+ break;
+ case MFI_DCMD_CTRL_FLUSHCACHE:
+ opcode = "CTRL_FLUSHCACHE";
+ break;
+ case MFI_DCMD_CTRL_SHUTDOWN:
+ opcode = "CTRL_SHUTDOWN";
+ break;
+ case MFI_DCMD_CTRL_EVENT_GETINFO:
+ opcode = "EVENT_GETINFO";
+ break;
+ case MFI_DCMD_CTRL_EVENT_GET:
+ opcode = "EVENT_GET";
+ break;
+ case MFI_DCMD_CTRL_EVENT_WAIT:
+ opcode = "EVENT_WAIT";
+ break;
+ case MFI_DCMD_LD_GET_LIST:
+ opcode = "LD_GET_LIST";
+ break;
+ case MFI_DCMD_LD_GET_INFO:
+ opcode = "LD_GET_INFO";
+ break;
+ case MFI_DCMD_LD_GET_PROP:
+ opcode = "LD_GET_PROP";
+ break;
+ case MFI_DCMD_LD_SET_PROP:
+ opcode = "LD_SET_PROP";
+ break;
+ case MFI_DCMD_CLUSTER:
+ opcode = "CLUSTER";
+ break;
+ case MFI_DCMD_CLUSTER_RESET_ALL:
+ opcode = "CLUSTER_RESET_ALL";
+ break;
+ case MFI_DCMD_CLUSTER_RESET_LD:
+ opcode = "CLUSTER_RESET_LD";
+ break;
+ default:
+ opcode = "UNKNOWN";
+ break;
+ }
+
+ device_printf(dev, "cmd=MFI_CMD_DCMD opcode=%s data_len=%d\n",
+ opcode, hdr->data_len);
+ mfi_print_frame_flags(dev, hdr->flags);
+ mfi_print_sgl(hdr, &dcmd->sgl, hdr->sg_count);
+
+}
+
+static void
+mfi_print_generic_frame(struct mfi_softc *sc, struct mfi_command *cm)
+{
+ hexdump(cm->cm_frame, cm->cm_total_frame_size, NULL, HD_OMIT_CHARS);
+}
+
+void
+mfi_print_cmd(struct mfi_command *cm)
+{
+ device_t dev;
+ struct mfi_softc *sc;
+
+ sc = cm->cm_sc;
+ dev = sc->mfi_dev;
+
+ device_printf(dev, "cm=%p index=%d total_frame_size=%d "
+ "extra_frames=%d\n", cm, cm->cm_index, cm->cm_total_frame_size,
+ cm->cm_extra_frames);
+ device_printf(dev, "flags=%b\n", cm->cm_flags,
+ "\20"
+ "\1MAPPED"
+ "\2DATAIN"
+ "\3DATAOUT"
+ "\4COMPLETED"
+ "\5POLLED"
+ "\6Q_FREE"
+ "\7Q_READY"
+ "\10Q_BUSY");
+
+ switch (cm->cm_frame->header.cmd) {
+ case MFI_CMD_DCMD:
+ mfi_print_dcmd(sc, dev, cm);
+ break;
+ case MFI_CMD_LD_READ:
+ case MFI_CMD_LD_WRITE:
+ mfi_print_ldio(sc, dev, cm);
+ break;
+ default:
+ mfi_print_generic_frame(sc, cm);
+ break;
+ }
+
+ return;
+}
+
+void
+mfi_dump_cmds(struct mfi_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < sc->mfi_total_cmds; i++)
+ mfi_print_generic_frame(sc, &sc->mfi_commands[i]);
+}
+
+void
+mfi_validate_sg(struct mfi_softc *sc, struct mfi_command *cm,
+ const char *function, int line)
+{
+ struct mfi_frame_header *hdr;
+ int i;
+ uint32_t count = 0, data_len;
+
+ hdr = &cm->cm_frame->header;
+ count = 0;
+ for (i = 0; i < hdr->sg_count; i++) {
+ count += cm->cm_sg->sg32[i].len;
+ }
+ /*
+ count++;
+ */
+ data_len = hdr->data_len;
+ switch (hdr->cmd) {
+ case MFI_CMD_LD_READ:
+ case MFI_CMD_LD_WRITE:
+ data_len = data_len * 512;
+ case MFI_CMD_DCMD:
+ if (count != data_len) {
+ device_printf(sc->mfi_dev,
+ "%s %d COMMAND %p S/G count bad %d %d %d 0x%jx\n",
+ function, line, cm, count, data_len, cm->cm_len,
+ (intmax_t)pmap_kextract((vm_offset_t)cm->cm_data));
+ MFI_PRINT_CMD(cm);
+ }
+ }
+}
+
+#endif
--- /dev/null
+++ sys/dev/mfi/mfi_linux.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_linux.c,v 1.2 2006/11/14 16:48:00 ambrisko 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 <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_util.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+
+/* There are multiple ioctl number ranges that need to be handled */
+#define MFI_LINUX_IOCTL_MIN 0x4d00
+#define MFI_LINUX_IOCTL_MAX 0x4d04
+
+static linux_ioctl_function_t mfi_linux_ioctl;
+static struct linux_ioctl_handler mfi_linux_handler = {mfi_linux_ioctl,
+ MFI_LINUX_IOCTL_MIN,
+ MFI_LINUX_IOCTL_MAX};
+
+SYSINIT (mfi_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_register_handler, &mfi_linux_handler);
+SYSUNINIT(mfi_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_unregister_handler, &mfi_linux_handler);
+
+static struct linux_device_handler mfi_device_handler =
+ { "mfi", "megaraid_sas", "mfi0", "megaraid_sas_ioctl_node", -1, 0, 1};
+
+SYSINIT (mfi_register2, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_device_register_handler, &mfi_device_handler);
+SYSUNINIT(mfi_unregister2, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_device_unregister_handler, &mfi_device_handler);
+
+static int
+mfi_linux_modevent(module_t mod, int cmd, void *data)
+{
+ return (0);
+}
+
+DEV_MODULE(mfi_linux, mfi_linux_modevent, NULL);
+MODULE_DEPEND(mfi, linux, 1, 1, 1);
+
+static int
+mfi_linux_ioctl(d_thread_t *p, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+ u_long cmd = args->cmd;
+
+ switch (cmd) {
+ case MFI_LINUX_CMD:
+ cmd = MFI_LINUX_CMD_2;
+ break;
+ case MFI_LINUX_SET_AEN:
+ cmd = MFI_LINUX_SET_AEN_2;
+ break;
+ }
+
+ if ((error = fget(p, args->fd, &fp)) != 0)
+ return (error);
+ error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
+ fdrop(fp, p);
+ return (error);
+}
Index: mfivar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfivar.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfivar.h -L sys/dev/mfi/mfivar.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfivar.h
+++ sys/dev/mfi/mfivar.h
@@ -23,13 +23,41 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
#ifndef _MFIVAR_H
#define _MFIVAR_H
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.11 2007/08/25 23:58:45 scottl Exp $");
+
+#include <sys/lock.h>
+#include <sys/sx.h>
/*
* SCSI structures and definitions are used from here, but no linking
@@ -44,9 +72,12 @@
};
struct mfi_softc;
+struct disk;
+struct ccb_hdr;
struct mfi_command {
TAILQ_ENTRY(mfi_command) cm_link;
+ time_t cm_timestamp;
struct mfi_softc *cm_sc;
union mfi_frame *cm_frame;
uint32_t cm_frame_busaddr;
@@ -68,16 +99,29 @@
#define MFI_ON_MFIQ_READY (1<<6)
#define MFI_ON_MFIQ_BUSY (1<<7)
#define MFI_ON_MFIQ_MASK ((1<<5)|(1<<6)|(1<<7))
+ int cm_aen_abort;
void (* cm_complete)(struct mfi_command *cm);
void *cm_private;
+ int cm_index;
+ int cm_error;
+};
+
+struct mfi_disk {
+ TAILQ_ENTRY(mfi_disk) ld_link;
+ device_t ld_dev;
+ int ld_id;
+ int ld_unit;
+ struct mfi_softc *ld_controller;
+ struct mfi_ld_info *ld_info;
+ struct disk *ld_disk;
+ int ld_flags;
+#define MFI_DISK_FLAGS_OPEN 0x01
+#define MFI_DISK_FLAGS_DISABLED 0x02
};
-struct mfi_ld {
- TAILQ_ENTRY(mfi_ld) ld_link;
- device_t ld_disk;
- uint64_t ld_sectors;
- uint32_t ld_secsize;
- int ld_id;
+struct mfi_aen {
+ TAILQ_ENTRY(mfi_aen) aen_link;
+ struct proc *p;
};
struct mfi_softc {
@@ -86,6 +130,9 @@
#define MFI_FLAGS_SG64 (1<<0)
#define MFI_FLAGS_QFRZN (1<<1)
#define MFI_FLAGS_OPEN (1<<2)
+#define MFI_FLAGS_STOP (1<<3)
+#define MFI_FLAGS_1064R (1<<4)
+#define MFI_FLAGS_1078 (1<<5)
struct mfi_hwcomms *mfi_comms;
TAILQ_HEAD(,mfi_command) mfi_free;
@@ -111,6 +158,15 @@
uint32_t mfi_frames_busaddr;
union mfi_frame *mfi_frames;
+ TAILQ_HEAD(,mfi_aen) mfi_aen_pids;
+ struct mfi_command *mfi_aen_cm;
+ uint32_t mfi_aen_triggered;
+ uint32_t mfi_poll_waiting;
+ struct selinfo mfi_select;
+ int mfi_delete_busy_volumes;
+ int mfi_keep_deleted_volumes;
+ int mfi_detaching;
+
bus_dma_tag_t mfi_sense_dmat;
bus_dmamap_t mfi_sense_dmamap;
uint32_t mfi_sense_busaddr;
@@ -122,7 +178,6 @@
struct intr_config_hook mfi_ich;
eventhandler_tag eh;
- int mfi_probe_count;
/*
* Allocation for the command array. Used as an indexable array to
@@ -139,33 +194,39 @@
*/
int mfi_max_fw_cmds;
/*
- * Max number of S/G elements the firmware can handle
- */
- int mfi_max_fw_sgl;
- /*
* How many S/G elements we'll ever actually use
*/
- int mfi_total_sgl;
+ int mfi_max_sge;
/*
* How many bytes a compound frame is, including all of the extra frames
* that are used for S/G elements.
*/
- int mfi_frame_size;
+ int mfi_cmd_size;
/*
* How large an S/G element is. Used to calculate the number of single
* frames in a command.
*/
- int mfi_sgsize;
+ int mfi_sge_size;
/*
* Max number of sectors that the firmware allows
*/
uint32_t mfi_max_io;
- TAILQ_HEAD(,mfi_ld) mfi_ld_tqh;
+ TAILQ_HEAD(,mfi_disk) mfi_ld_tqh;
eventhandler_tag mfi_eh;
struct cdev *mfi_cdev;
+ TAILQ_HEAD(, ccb_hdr) mfi_cam_ccbq;
+ struct mfi_command * (* mfi_cam_start)(void *);
+ struct callout mfi_watchdog_callout;
struct mtx mfi_io_lock;
+ struct sx mfi_config_lock;
+
+ /* Controller type specific interfaces */
+ void (*mfi_enable_intr)(struct mfi_softc *sc);
+ int32_t (*mfi_read_fw_status)(struct mfi_softc *sc);
+ int (*mfi_check_clear_intr)(struct mfi_softc *sc);
+ void (*mfi_issue_cmd)(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
};
extern int mfi_attach(struct mfi_softc *);
@@ -173,6 +234,8 @@
extern int mfi_shutdown(struct mfi_softc *);
extern void mfi_startio(struct mfi_softc *);
extern void mfi_disk_complete(struct bio *);
+extern int mfi_disk_disable(struct mfi_disk *);
+extern void mfi_disk_enable(struct mfi_disk *);
extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
#define MFIQ_ADD(sc, qname) \
@@ -314,4 +377,21 @@
MALLOC_DECLARE(M_MFIBUF);
+#define MFI_CMD_TIMEOUT 30
+
+#ifdef MFI_DEBUG
+extern void mfi_print_cmd(struct mfi_command *cm);
+extern void mfi_dump_cmds(struct mfi_softc *sc);
+extern void mfi_validate_sg(struct mfi_softc *, struct mfi_command *, const char *, int );
+#define MFI_PRINT_CMD(cm) mfi_print_cmd(cm)
+#define MFI_DUMP_CMDS(sc) mfi_dump_cmds(sc)
+#define MFI_VALIDATE_CMD(sc, cm) mfi_validate_sg(sc, cm, __FUNCTION__, __LINE__)
+#else
+#define MFI_PRINT_CMD(cm)
+#define MFI_DUMP_CMDS(sc)
+#define MFI_VALIDATE_CMD(sc, cm)
+#endif
+
+extern void mfi_release_command(struct mfi_command *cm);
+
#endif /* _MFIVAR_H */
More information about the Midnightbsd-cvs
mailing list