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:
parent
f00d84860a
commit
741367d5a5
@ -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
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
90
sys/dev/mfi/mfi_linux.c
Normal 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);
|
||||
}
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
8
sys/modules/mfi/mfi_linux/Makefile
Normal file
8
sys/modules/mfi/mfi_linux/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/mfi
|
||||
|
||||
KMOD= mfi_linux
|
||||
SRCS= mfi_linux.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user