- 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
This commit is contained in:
parent
3fe3dba179
commit
441f6d5dca
@ -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 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
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 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user