Add in a bunch of things to the mfi driver:

- Linux ioctl support, with the other Linux changes MegaCli
	will run if you mount linprocfs & linsysfs then set
	sysctl compat.linux.osrelease=2.6.12 or similar.  This works
	on i386.  It should work on amd64 but not well tested yet.
	StoreLib may or may not work.  Remember to kldload mfi_linux.
      - Add in AEN (Async Event Notification) support so we can
	get messages from the firmware when something happens.
	Not all messages are in defined in event detail.  Use
	event_log to try to figure out what happened.
      - Try to implement something like SIGIO for StoreLib.  Since
	mrmonitor doesn't work right I can't fully test it.  StoreLib
	works best with the rh9 base.  In theory mrmonitor isn't
	needed due to native driver support of AEN :-)
Now we can configure and monitor the RAID better.

Submitted by:	IronPort Systems.
This commit is contained in:
Doug Ambrisko 2006-05-18 23:30:48 +00:00
parent f00d84860a
commit 741367d5a5
12 changed files with 1147 additions and 32 deletions

View File

@ -699,6 +699,7 @@ dev/mem/memdev.c optional mem
dev/mfi/mfi.c optional mfi
dev/mfi/mfi_pci.c optional mfi pci
dev/mfi/mfi_disk.c optional mfi
dev/mfi/mfi_linux.c optional mfi compat_linux
dev/mii/acphy.c optional miibus | acphy
dev/mii/amphy.c optional miibus | amphy
dev/mii/bmtphy.c optional miibus | bmtphy

View File

@ -242,6 +242,7 @@ compat/linux/linux_sysctl.c optional compat_linux32
compat/linux/linux_uid16.c optional compat_linux32
compat/linux/linux_util.c optional compat_linux32
dev/amr/amr_linux.c optional compat_linux32 amr
dev/mfi/mfi_linux.c optional compat_linux32 mfi
#
# Windows NDIS driver support
#

View File

@ -116,6 +116,7 @@ MAC_TEST opt_dontuse.h
MD_ROOT opt_md.h
MD_ROOT_SIZE opt_md.h
MFI_DEBUG opt_mfi.h
MFI_DECODE_LOG opt_mfi.h
MPROF_BUFFERS opt_mprof.h
MPROF_HASH_SIZE opt_mprof.h
MUTEX_WAKE_ALL

View File

@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.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>
@ -40,6 +42,8 @@ __FBSDID("$FreeBSD$");
#include <sys/bus_dma.h>
#include <sys/bio.h>
#include <sys/ioccom.h>
#include <sys/uio.h>
#include <sys/proc.h>
#include <machine/bus.h>
#include <machine/resource.h>
@ -53,6 +57,9 @@ 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_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 void mfi_data_cb(void *, bus_dma_segment_t *, int, int);
static void mfi_startup(void *arg);
static void mfi_intr(void *arg);
@ -63,17 +70,23 @@ 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_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 id, uint64_t, uint32_t);
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 *);
/* 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,
@ -81,12 +94,13 @@ static struct cdevsw mfi_cdevsw = {
.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 int
mfi_transition_firmware(struct mfi_softc *sc)
@ -160,6 +174,7 @@ mfi_attach(struct mfi_softc *sc)
mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
TAILQ_INIT(&sc->mfi_ld_tqh);
TAILQ_INIT(&sc->mfi_aen_pids);
mfi_initq_free(sc);
mfi_initq_ready(sc);
@ -315,10 +330,8 @@ mfi_attach(struct mfi_softc *sc)
if ((error = mfi_get_controller_info(sc)) != 0)
return (error);
#if 0
if ((error = mfi_setup_aen(sc)) != 0)
if ((error = mfi_aen_setup(sc, 0), 0) != 0)
return (error);
#endif
/*
* Set up the interrupt handler. XXX This should happen in
@ -360,6 +373,8 @@ mfi_attach(struct mfi_softc *sc)
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;
@ -382,7 +397,7 @@ mfi_alloc_commands(struct mfi_softc *sc)
for (i = 0; i < ncmds; i++) {
cm = &sc->mfi_commands[i];
cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
sc->mfi_frame_size * i);
cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
sc->mfi_frame_size * i;
@ -524,6 +539,90 @@ mfi_get_controller_info(struct mfi_softc *sc)
return (error);
}
static int
mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state *log_state)
{
struct mfi_command *cm;
struct mfi_dcmd_frame *dcmd;
int error;
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
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_evt_log_state);
dcmd->opcode = MFI_DCMD_CTRL_EVENT_GETINFO;
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 = log_state;
cm->cm_len = sizeof(struct mfi_evt_log_state);
if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "Controller info buffer map failed");
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 state\n");
sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
MFI_SECTOR_LEN;
mfi_release_command(cm);
return (0);
}
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
mfi_release_command(cm);
return (error);
}
static int
mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
{
struct mfi_evt_log_state log_state;
union mfi_evt class_locale;
int error = 0;
uint32_t seq;
class_locale.members.reserved = 0;
class_locale.members.locale = MFI_EVT_LOCALE_ALL;
class_locale.members.class = MFI_EVT_CLASS_DEBUG;
if (seq_start == 0) {
error = mfi_get_log_state(sc, &log_state);
if (error)
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.
*/
#if 0
for (seq = log_state.shutdown_seq_num;
seq <= log_state.newest_seq_num; seq++) {
mfi_get_entry(sc, seq);
}
#endif
seq = log_state.shutdown_seq_num + 1;
} else
seq = seq_start;
mfi_aen_register(sc, seq, class_locale.word);
return 0;
}
static int
mfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
{
@ -638,7 +737,6 @@ mfi_intr(void *arg)
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];
@ -673,7 +771,8 @@ mfi_shutdown(struct mfi_softc *sc)
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
/* 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);
@ -831,6 +930,426 @@ mfi_ldprobe_tur_complete(struct mfi_command *cm)
mfi_ldprobe_capacity(sc, hdr->target_id);
}
#ifndef MFI_DECODE_LOG
static void
mfi_decode_log(struct mfi_softc *sc, struct mfi_log_detail *detail)
{
switch (detail->arg_type) {
default:
device_printf(sc->mfi_dev, "%d - Log entry type %d\n",
detail->seq,
detail->arg_type
);
break;
}
}
#else
#include <dev/mfi/mfilog.h>
#include <dev/mfi/mfi_log.c>
#endif
static void
mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
{
switch (detail->arg_type) {
case MR_EVT_ARGS_NONE:
/* Try to get info from log entry */
mfi_get_entry(sc, detail->seq);
break;
case MR_EVT_ARGS_CDB_SENSE:
device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) CDB %*D"
"Sense %*D\n: %s",
detail->seq,
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 - VD %02d/%d "
"event: %s\n",
detail->seq,
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 - VD %02d/%d "
"count %lld: %s\n",
detail->seq,
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 - VD %02d/%d "
"lba %lld: %s\n",
detail->seq,
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 - VD %02d/%d "
"owner changed: prior %d, new %d: %s\n",
detail->seq,
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 - VD %02d/%d "
"lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
detail->seq,
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 - VD %02d/%d "
"progress %d%% in %ds: %s\n",
detail->seq,
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 - VD %02d/%d "
"state prior %d new %d: %s\n",
detail->seq,
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 - VD %02d/%d "
"strip %lld: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"event: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"err %d: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"lba %lld: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"lba %lld VD %02d/%d: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"progress %d%% seconds %ds: %s\n",
detail->seq,
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 - PD %02d(e%d/s%d) "
"state prior %d new %d: %s\n",
detail->seq,
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 - PCI 0x04%x 0x04%x "
"0x04%x 0x04%x: %s\n",
detail->seq,
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 - Rebuild rate %d: %s\n",
detail->seq,
detail->args.rate,
detail->description
);
break;
case MR_EVT_ARGS_TIME:
device_printf(sc->mfi_dev, "%d - Adapter ticks %d "
"elapsed %ds: %s\n",
detail->seq,
detail->args.time.rtc,
detail->args.time.elapsedSeconds,
detail->description
);
break;
case MR_EVT_ARGS_ECC:
device_printf(sc->mfi_dev, "%d - Adapter ECC %x,%x: %s: %s\n",
detail->seq,
detail->args.ecc.ecar,
detail->args.ecc.elog,
detail->args.ecc.str,
detail->description
);
break;
default:
device_printf(sc->mfi_dev, "%d - Type %d: %s\n",
detail->seq,
detail->arg_type, detail->description
);
}
}
static int
mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
{
struct mfi_command *cm;
struct mfi_dcmd_frame *dcmd;
union mfi_evt current_aen, prior_aen;
struct mfi_evt_detail *ed;
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);
}
}
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);
ed = malloc(sizeof(struct mfi_evt_detail), M_MFIBUF,
M_NOWAIT | M_ZERO);
if (ed == NULL) {
mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
mtx_unlock(&sc->mfi_io_lock);
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_evt_detail);
dcmd->opcode = MFI_DCMD_CTRL_EVENT_WAIT;
((uint32_t *)&dcmd->mbox)[0] = seq;
((uint32_t *)&dcmd->mbox)[1] = locale;
cm->cm_sg = &dcmd->sgl;
cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
cm->cm_flags = MFI_CMD_DATAIN;
cm->cm_data = ed;
cm->cm_len = sizeof(struct mfi_evt_detail);
cm->cm_complete = mfi_aen_complete;
sc->mfi_aen_cm = cm;
mfi_enqueue_ready(cm);
mfi_startio(sc);
return (0);
}
static void
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;
int seq = 0, aborted = 0;
sc = cm->cm_sc;
hdr = &cm->cm_frame->header;
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)
selwakeup(&sc->mfi_select);
detail = cm->cm_data;
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_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
aen_link);
psignal(mfi_aen_entry->p, SIGIO);
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);
/* 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);
}
}
static int
mfi_get_entry(struct mfi_softc *sc, int seq)
{
struct mfi_command *cm;
struct mfi_dcmd_frame *dcmd;
struct mfi_log_detail *ed;
int error;
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);
ed = malloc(sizeof(struct mfi_log_detail), M_MFIBUF, M_NOWAIT | M_ZERO);
if (ed == NULL) {
mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
mtx_unlock(&sc->mfi_io_lock);
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_log_detail);
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 = ed;
cm->cm_len = sizeof(struct mfi_evt_detail);
if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "Controller info buffer map failed");
free(ed, M_MFIBUF);
mfi_release_command(cm);
return (error);
}
if ((error = mfi_polled_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev, "Failed to get controller entry\n");
sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
MFI_SECTOR_LEN;
free(ed, M_MFIBUF);
mfi_release_command(cm);
return (0);
}
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
mfi_decode_log(sc, ed);
mtx_lock(&sc->mfi_io_lock);
free(cm->cm_data, M_MFIBUF);
mfi_release_command(cm);
mtx_unlock(&sc->mfi_io_lock);
return (0);
}
static int
mfi_ldprobe_capacity(struct mfi_softc *sc, int id)
{
@ -955,7 +1474,7 @@ mfi_bio_command(struct mfi_softc *sc)
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);
@ -1181,6 +1700,41 @@ mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
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;
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);
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;
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);
}
return (0);
}
int
mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
{
@ -1237,10 +1791,19 @@ 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;
sc = dev->si_drv1;
sc->mfi_flags &= ~MFI_FLAGS_OPEN;
TAILQ_FOREACH(mfi_aen_entry, &sc->mfi_aen_pids, aen_link) {
if (mfi_aen_entry->p == curproc) {
TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
aen_link);
printf("REMOVED pid %d\n",mfi_aen_entry->p->p_pid);
free(mfi_aen_entry, M_MFIBUF);
}
}
return (0);
}
@ -1266,10 +1829,52 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
sizeof(struct mfi_qstat));
break;
default:
error = ENOENT;
error = ENOIOCTL;
break;
}
break;
case 0xc1144d01: /* 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 0x400c4d03: /* 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:
error = ENOENT;
break;
@ -1277,3 +1882,198 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
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;
uint32_t *sense_ptr;
uint32_t context;
uint8_t *data = NULL, *temp;
int i;
int error;
sc = dev->si_drv1;
error = 0;
switch (cmd) {
case 0xc1144d01: /* 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);
/*
* 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,
l_ioc.lioc_sgl_off); /* Linux can do 2 frames ? */
cm->cm_total_frame_size = l_ioc.lioc_sgl_off;
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
| MFI_CMD_POLLED;
cm->cm_len = cm->cm_frame->header.data_len;
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
M_WAITOK | M_ZERO);
/* restore header context */
cm->cm_frame->header.context = context;
temp = data;
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
error = copyin(l_ioc.lioc_sgl[i].iov_base,
temp,
l_ioc.lioc_sgl[i].iov_len);
if (error != 0) {
device_printf(sc->mfi_dev,
"Copy in failed");
goto out;
}
temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
if (l_ioc.lioc_sense_len) {
sense_ptr =
(void *)&cm->cm_frame->bytes[l_ioc.lioc_sense_off];
*sense_ptr = cm->cm_sense_busaddr;
}
if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller info buffer map failed");
goto out;
}
if ((error = mfi_polled_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller polled failed");
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);
temp = data;
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
error = copyout(temp,
l_ioc.lioc_sgl[i].iov_base,
l_ioc.lioc_sgl[i].iov_len);
if (error != 0) {
device_printf(sc->mfi_dev,
"Copy out failed");
goto out;
}
temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
if (l_ioc.lioc_sense_len) {
/* copy out sense */
sense_ptr = (void *)
&l_ioc.lioc_frame.raw[l_ioc.lioc_sense_off];
temp = 0;
temp += cm->cm_sense_busaddr;
error = copyout(temp, sense_ptr,
l_ioc.lioc_sense_len);
if (error != 0) {
device_printf(sc->mfi_dev,
"Copy out failed");
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");
goto out;
}
out:
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 0x400c4d03: /* 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);
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);
}
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;
printf("MFI POLL\n");
if (poll_events & (POLLIN | POLLRDNORM)) {
if (sc->mfi_aen_triggered != 0)
revents |= poll_events & (POLLIN | POLLRDNORM);
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);
sc->mfi_poll_waiting = 0;
}
}
return revents;
}

View File

@ -32,8 +32,10 @@ __FBSDID("$FreeBSD$");
#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>

View File

@ -43,5 +43,28 @@ union mfi_statrequest {
struct mfi_qstat ms_qstat;
};
#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;
struct iovec lioc_sgl[MAX_LINUX_IOCTL_SGE];
} __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;

90
sys/dev/mfi/mfi_linux.c Normal file
View File

@ -0,0 +1,90 @@
/*-
* 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$");
#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>
/* 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;
if ((error = fget(p, args->fd, &fp)) != 0)
return (error);
error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p);
fdrop(fp, p);
return (error);
}

View File

@ -34,11 +34,13 @@ __FBSDID("$FreeBSD$");
#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>

View File

@ -120,7 +120,7 @@ typedef enum {
#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
@ -218,27 +218,27 @@ typedef enum {
} 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;
/*
@ -508,7 +508,7 @@ struct mfi_ctrl_info {
#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
@ -556,4 +556,175 @@ struct mfi_ctrl_info {
uint8_t pad[0x800 - 0x6a0];
} __packed;
/* keep track of an event. */
union mfi_evt {
struct {
uint16_t locale;
uint8_t reserved;
uint8_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;
/* SAS log detail guessed at */
struct mfi_log_detail {
uint32_t something1;
uint32_t something2;
uint32_t seq;
uint32_t something3;
uint32_t arg_type;
uint8_t reserved1[15];
union {
uint8_t b[96];
} args;
char description[128];
} __packed;
#endif /* _MFIREG_H */

View File

@ -67,6 +67,7 @@ struct mfi_command {
#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;
};
@ -79,6 +80,11 @@ struct mfi_ld {
int ld_id;
};
struct mfi_aen {
TAILQ_ENTRY(mfi_aen) aen_link;
struct proc *p;
};
struct mfi_softc {
device_t mfi_dev;
int mfi_flags;
@ -110,6 +116,12 @@ struct mfi_softc {
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;
bus_dma_tag_t mfi_sense_dmat;
bus_dmamap_t mfi_sense_dmamap;
uint32_t mfi_sense_busaddr;

View File

@ -2,6 +2,10 @@
.PATH: ${.CURDIR}/../../dev/mfi
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
SUBDIR= mfi_linux
.endif
KMOD= mfi
SRCS= mfi.c mfi_pci.c mfi_disk.c
SRCS+= opt_mfi.h

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/mfi
KMOD= mfi_linux
SRCS= mfi_linux.c
.include <bsd.kmod.mk>