summaryrefslogtreecommitdiffstats
path: root/sys/dev/mfi
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2006-10-16 04:18:38 +0000
committerscottl <scottl@FreeBSD.org>2006-10-16 04:18:38 +0000
commit012e27daa11e6811c981d259dc0bb43ce54792a0 (patch)
treef9ab8d12d2f604c26a086cb17a9be1266d38f051 /sys/dev/mfi
parent9b96c4f62e46173803871c0f01be5afa7d5de80d (diff)
downloadFreeBSD-src-012e27daa11e6811c981d259dc0bb43ce54792a0.zip
FreeBSD-src-012e27daa11e6811c981d259dc0bb43ce54792a0.tar.gz
- Add a command validator for use in debugging.
- Fix the locking protocol to eliminate races between normal I/O and AENs. - Various small improvements and usability tweaks. Sponsored by: IronPort Portions Submitted by: Doug Ambrisko
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r--sys/dev/mfi/mfi.c182
-rw-r--r--sys/dev/mfi/mfi_debug.c35
-rw-r--r--sys/dev/mfi/mfi_disk.c24
-rw-r--r--sys/dev/mfi/mfireg.h231
-rw-r--r--sys/dev/mfi/mfivar.h6
5 files changed, 425 insertions, 53 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index f611370..823f2cc 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ioccom.h>
#include <sys/uio.h>
#include <sys/proc.h>
+#include <sys/signalvar.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -342,8 +343,12 @@ mfi_attach(struct mfi_softc *sc)
if ((error = mfi_get_controller_info(sc)) != 0)
return (error);
- if ((error = mfi_aen_setup(sc, 0), 0) != 0)
+ mtx_lock(&sc->mfi_io_lock);
+ if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
/*
* Set up the interrupt handler. XXX This should happen in
@@ -437,6 +442,7 @@ mfi_alloc_commands(struct mfi_softc *sc)
static void
mfi_release_command(struct mfi_command *cm)
{
+ struct mfi_frame_header *hdr;
uint32_t *hdr_data;
/*
@@ -447,12 +453,18 @@ mfi_release_command(struct mfi_command *cm)
hdr_data[0] = 0;
hdr_data[1] = 0;
+ hdr = &cm->cm_frame->header;
+ if (hdr->sg_count) {
+ cm->cm_sg->sg32[0].len = 0;
+ cm->cm_sg->sg32[0].addr = 0;
+ }
cm->cm_extra_frames = 0;
cm->cm_flags = 0;
cm->cm_complete = NULL;
cm->cm_private = NULL;
cm->cm_sg = 0;
cm->cm_total_frame_size = 0;
+
mfi_enqueue_free(cm);
}
@@ -511,6 +523,7 @@ mfi_comms_init(struct mfi_softc *sc)
struct mfi_init_qinfo *qinfo;
int error;
+ mtx_lock(&sc->mfi_io_lock);
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
@@ -536,9 +549,11 @@ mfi_comms_init(struct mfi_softc *sc)
if ((error = mfi_polled_command(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);
}
@@ -562,6 +577,7 @@ mfi_get_controller_info(struct mfi_softc *sc)
device_printf(sc->mfi_dev, "Controller info buffer map failed\n");
free(ci, M_MFIBUF);
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
}
@@ -597,7 +613,6 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
struct mfi_command *cm = NULL;
int error;
- mtx_lock(&sc->mfi_io_lock);
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
(void **)log_state, sizeof(**log_state));
if (error)
@@ -621,7 +636,6 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
out:
if (cm)
mfi_release_command(cm);
- mtx_unlock(&sc->mfi_io_lock);
return (error);
}
@@ -669,6 +683,8 @@ mfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
struct mfi_frame_header *hdr;
int tm = MFI_POLL_TIMEOUT_SECS * 1000000;
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
hdr = &cm->cm_frame->header;
hdr->cmd_status = 0xff;
hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
@@ -772,7 +788,9 @@ mfi_startup(void *arg)
config_intrhook_disestablish(&sc->mfi_ich);
mfi_enable_intr(sc);
+ mtx_lock(&sc->mfi_io_lock);
mfi_ldprobe(sc);
+ mtx_unlock(&sc->mfi_io_lock);
}
static void
@@ -787,6 +805,7 @@ mfi_intr(void *arg)
status = MFI_READ4(sc, MFI_OSTS);
if ((status & MFI_OSTS_INTR_VALID) == 0)
return;
+
MFI_WRITE4(sc, MFI_OSTS, status);
pi = sc->mfi_comms->hw_pi;
@@ -801,10 +820,15 @@ mfi_intr(void *arg)
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;
}
@@ -817,9 +841,10 @@ mfi_shutdown(struct mfi_softc *sc)
mtx_lock(&sc->mfi_io_lock);
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
- mtx_unlock(&sc->mfi_io_lock);
- if (error)
+ if (error) {
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
+ }
if (sc->mfi_aen_cm != NULL)
mfi_abort(sc, sc->mfi_aen_cm);
@@ -832,6 +857,7 @@ mfi_shutdown(struct mfi_softc *sc)
}
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
}
@@ -850,7 +876,8 @@ mfi_ldprobe(struct mfi_softc *sc)
struct mfi_ld_list *list = NULL;
int error, i;
- mtx_lock(&sc->mfi_io_lock);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
(void **)&list, sizeof(*list));
if (error)
@@ -870,13 +897,13 @@ mfi_ldprobe(struct mfi_softc *sc)
}
for (i = 0; i < list->ld_count; i++)
- mfi_add_ld(sc, list->ld_list[i].ld.target_id);
+ mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
out:
if (list)
free(list, M_MFIBUF);
if (cm)
mfi_release_command(cm);
- mtx_unlock(&sc->mfi_io_lock);
+
return;
}
@@ -1175,7 +1202,7 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
struct mfi_dcmd_frame *dcmd;
union mfi_evt current_aen, prior_aen;
struct mfi_evt_detail *ed = NULL;
- int error;
+ int error = 0;
current_aen.word = locale;
if (sc->mfi_aen_cm != NULL) {
@@ -1195,12 +1222,11 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
}
}
- mtx_lock(&sc->mfi_io_lock);
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
(void **)&ed, sizeof(*ed));
- mtx_unlock(&sc->mfi_io_lock);
- if (error)
- return (error);
+ if (error) {
+ goto out;
+ }
dcmd = &cm->cm_frame->dcmd;
((uint32_t *)&dcmd->mbox)[0] = seq;
@@ -1213,7 +1239,8 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
mfi_enqueue_ready(cm);
mfi_startio(sc);
- return (0);
+out:
+ return (error);
}
static void
@@ -1222,7 +1249,7 @@ 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;
+ struct mfi_aen *mfi_aen_entry, *tmp;
int seq = 0, aborted = 0;
sc = cm->cm_sc;
@@ -1236,17 +1263,25 @@ mfi_aen_complete(struct mfi_command *cm)
aborted = 1;
} else {
sc->mfi_aen_triggered = 1;
- if (sc->mfi_poll_waiting)
+ 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(mfi_aen_entry, &sc->mfi_aen_pids, aen_link) {
+ 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);
}
}
@@ -1258,9 +1293,7 @@ mfi_aen_complete(struct mfi_command *cm)
/* set it up again so the driver can catch more events */
if (!aborted) {
- mtx_unlock(&sc->mfi_io_lock);
mfi_aen_setup(sc, seq);
- mtx_lock(&sc->mfi_io_lock);
}
}
@@ -1276,20 +1309,15 @@ mfi_get_entry(struct mfi_softc *sc, int seq)
int i;
int size;
- 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);
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) {
- mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
- mtx_unlock(&sc->mfi_io_lock);
return (ENOMEM);
}
@@ -1334,10 +1362,8 @@ mfi_get_entry(struct mfi_softc *sc, int seq)
}
}
- mtx_lock(&sc->mfi_io_lock);
free(cm->cm_data, M_MFIBUF);
mfi_release_command(cm);
- mtx_unlock(&sc->mfi_io_lock);
return (0);
}
@@ -1408,7 +1434,7 @@ mfi_add_ld_complete(struct mfi_command *cm)
return;
}
- ld->ld_id = ld_info->ld_config.properties.ld.target_id;
+ ld->ld_id = ld_info->ld_config.properties.ld.v.target_id;
ld->ld_disk = child;
ld->ld_info = ld_info;
@@ -1420,7 +1446,7 @@ mfi_add_ld_complete(struct mfi_command *cm)
mtx_unlock(&Giant);
mtx_lock(&sc->mfi_io_lock);
}
-
+int mfi_io=0;
static struct mfi_command *
mfi_bio_command(struct mfi_softc *sc)
{
@@ -1469,7 +1495,7 @@ mfi_bio_command(struct mfi_softc *sc)
cm->cm_sg = &io->sgl;
cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
cm->cm_flags = flags;
-
+ mfi_io++;
return (cm);
}
@@ -1494,6 +1520,7 @@ mfi_bio_complete(struct mfi_command *cm)
mfi_release_command(cm);
mfi_disk_complete(bio);
+ mfi_io--;
}
void
@@ -1530,6 +1557,8 @@ mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
{
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,
@@ -1654,9 +1683,6 @@ mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
cm->cm_complete(cm);
else
wakeup(cm);
-
- sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
- mfi_startio(sc);
}
static int
@@ -1665,12 +1691,11 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
struct mfi_command *cm;
struct mfi_abort_frame *abort;
- mtx_lock(&sc->mfi_io_lock);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
if ((cm = mfi_dequeue_free(sc)) == NULL) {
- mtx_unlock(&sc->mfi_io_lock);
return (EBUSY);
}
- mtx_unlock(&sc->mfi_io_lock);
abort = &cm->cm_frame->abort;
abort->header.cmd = MFI_CMD_ABORT;
@@ -1683,12 +1708,10 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
sc->mfi_aen_cm->cm_aen_abort = 1;
mfi_mapcmd(sc, cm);
mfi_polled_command(sc, cm);
- mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
- mtx_unlock(&sc->mfi_io_lock);
while (sc->mfi_aen_cm != NULL) {
- tsleep(&sc->mfi_aen_cm, 0, "mfiabort", 5 * hz);
+ msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
}
return (0);
@@ -1741,7 +1764,10 @@ mfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
struct mfi_softc *sc;
sc = dev->si_drv1;
+
+ mtx_lock(&sc->mfi_io_lock);
sc->mfi_flags |= MFI_FLAGS_OPEN;
+ mtx_unlock(&sc->mfi_io_lock);
return (0);
}
@@ -1750,18 +1776,21 @@ 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;
+ 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(mfi_aen_entry, &sc->mfi_aen_pids, aen_link) {
+ 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);
}
@@ -1834,6 +1863,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
break;
}
default:
+ device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
error = ENOENT;
break;
}
@@ -1913,21 +1943,25 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
*sense_ptr = cm->cm_sense_busaddr;
}
+ mtx_lock(&sc->mfi_io_lock);
if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller info buffer map failed");
+ mtx_unlock(&sc->mfi_io_lock);
goto out;
}
if ((error = mfi_polled_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller polled failed");
+ mtx_unlock(&sc->mfi_io_lock);
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);
+ mtx_unlock(&sc->mfi_io_lock);
temp = data;
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
@@ -1967,6 +2001,14 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
goto out;
}
+ if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+ switch (cm->cm_frame->dcmd.opcode) {
+ case MFI_DCMD_CFG_CLEAR:
+ case MFI_DCMD_CFG_ADD:
+ /* mfi_ldrescan(sc); */
+ break;
+ }
+ }
out:
if (data)
free(data, M_MFIBUF);
@@ -1984,6 +2026,7 @@ out:
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,
@@ -1997,6 +2040,7 @@ out:
aen_link);
free(mfi_aen_entry, M_MFIBUF);
}
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
default:
@@ -2017,8 +2061,10 @@ mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
sc = dev->si_drv1;
if (poll_events & (POLLIN | POLLRDNORM)) {
- if (sc->mfi_aen_triggered != 0)
+ 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;
}
@@ -2028,13 +2074,58 @@ mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
if (poll_events & (POLLIN | POLLRDNORM)) {
sc->mfi_poll_waiting = 1;
selrecord(td, &sc->mfi_select);
- sc->mfi_poll_waiting = 0;
}
}
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)
{
@@ -2048,11 +2139,12 @@ mfi_timeout(void *data)
TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
if (sc->mfi_aen_cm == cm)
continue;
- if (cm->cm_timestamp < deadline) {
+ 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++;
}
}
@@ -2067,5 +2159,7 @@ mfi_timeout(void *data)
callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
mfi_timeout, sc);
+ if (0)
+ mfi_dump_all();
return;
}
diff --git a/sys/dev/mfi/mfi_debug.c b/sys/dev/mfi/mfi_debug.c
index 5cd2d35..515e6ed 100644
--- a/sys/dev/mfi/mfi_debug.c
+++ b/sys/dev/mfi/mfi_debug.c
@@ -46,6 +46,9 @@ __FBSDID("$FreeBSD$");
#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>
@@ -225,4 +228,36 @@ mfi_dump_cmds(struct mfi_softc *sc)
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
diff --git a/sys/dev/mfi/mfi_disk.c b/sys/dev/mfi/mfi_disk.c
index 909adcf..35de4df 100644
--- a/sys/dev/mfi/mfi_disk.c
+++ b/sys/dev/mfi/mfi_disk.c
@@ -103,6 +103,7 @@ mfi_disk_attach(device_t dev)
struct mfi_ld *ld;
uint64_t sectors;
uint32_t secsize;
+ char *state;
sc = device_get_softc(dev);
ld = device_get_ivars(dev);
@@ -117,8 +118,27 @@ mfi_disk_attach(device_t dev)
secsize = MFI_SECTOR_LEN;
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);
+ switch (ld->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;
+ }
+ device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n",
+ sectors / (1024 * 1024 / secsize), sectors,
+ ld->ld_info->ld_config.properties.name,
+ state);
sc->ld_disk = disk_alloc();
sc->ld_disk->d_drv1 = sc;
diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h
index 48a1382..d9df2c5 100644
--- a/sys/dev/mfi/mfireg.h
+++ b/sys/dev/mfi/mfireg.h
@@ -101,6 +101,8 @@ typedef enum {
/* 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,
@@ -110,6 +112,9 @@ typedef enum {
MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000,
MFI_DCMD_LD_SET_PROP = 0x03040000,
+ 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
@@ -244,6 +249,22 @@ typedef enum {
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
*/
@@ -456,6 +477,51 @@ struct mfi_info_component {
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 {
@@ -721,17 +787,117 @@ struct mfi_evt_list {
struct mfi_evt_detail event[1];
} __packed;
-struct mfi_ldref {
- uint8_t target_id;
- uint8_t reserved;
- uint16_t seq;
+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 {
- struct mfi_ldref ld;
+ union mfi_ld_ref ld;
uint8_t state;
uint8_t reserved2[3];
uint64_t size;
@@ -753,7 +919,7 @@ enum mfi_ld_state {
};
struct mfi_ld_props {
- struct mfi_ldref ld;
+ union mfi_ld_ref ld;
char name[16];
uint8_t default_cache_policy;
uint8_t access_policy;
@@ -814,4 +980,57 @@ struct mfi_ld_info {
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;
+
#endif /* _MFIREG_H */
diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h
index 1017cbf..7028cc4 100644
--- a/sys/dev/mfi/mfivar.h
+++ b/sys/dev/mfi/mfivar.h
@@ -92,6 +92,7 @@ struct mfi_softc {
#define MFI_FLAGS_SG64 (1<<0)
#define MFI_FLAGS_QFRZN (1<<1)
#define MFI_FLAGS_OPEN (1<<2)
+#define MFI_FLAGS_STOP (1<<3)
struct mfi_hwcomms *mfi_comms;
TAILQ_HEAD(,mfi_command) mfi_free;
@@ -327,11 +328,14 @@ MALLOC_DECLARE(M_MFIBUF);
#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_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
#endif /* _MFIVAR_H */
OpenPOWER on IntegriCloud