diff options
author | ambrisko <ambrisko@FreeBSD.org> | 2006-05-18 23:30:48 +0000 |
---|---|---|
committer | ambrisko <ambrisko@FreeBSD.org> | 2006-05-18 23:30:48 +0000 |
commit | 2f056812a1392832771de5b0dfbef07c6cd58edf (patch) | |
tree | bdf34234b5c8fd48d8bf0f3e68fb6a04622e7227 /sys/dev/mfi | |
parent | 0c235a1ed089c04da60996b550032ddc98d5d410 (diff) | |
download | FreeBSD-src-2f056812a1392832771de5b0dfbef07c6cd58edf.zip FreeBSD-src-2f056812a1392832771de5b0dfbef07c6cd58edf.tar.gz |
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.
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r-- | sys/dev/mfi/mfi.c | 818 | ||||
-rw-r--r-- | sys/dev/mfi/mfi_disk.c | 2 | ||||
-rw-r--r-- | sys/dev/mfi/mfi_ioctl.h | 23 | ||||
-rw-r--r-- | sys/dev/mfi/mfi_linux.c | 90 | ||||
-rw-r--r-- | sys/dev/mfi/mfi_pci.c | 2 | ||||
-rw-r--r-- | sys/dev/mfi/mfireg.h | 217 | ||||
-rw-r--r-- | sys/dev/mfi/mfivar.h | 12 |
7 files changed, 1132 insertions, 32 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index c4cc8f2..ec84384 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -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; @@ -525,6 +540,90 @@ mfi_get_controller_info(struct mfi_softc *sc) } 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) { struct mfi_frame_header *hdr; @@ -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; +} diff --git a/sys/dev/mfi/mfi_disk.c b/sys/dev/mfi/mfi_disk.c index dbba704..dc40e3b 100644 --- a/sys/dev/mfi/mfi_disk.c +++ b/sys/dev/mfi/mfi_disk.c @@ -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> diff --git a/sys/dev/mfi/mfi_ioctl.h b/sys/dev/mfi/mfi_ioctl.h index 6730ba2..7c4dae9 100644 --- a/sys/dev/mfi/mfi_ioctl.h +++ b/sys/dev/mfi/mfi_ioctl.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; diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c new file mode 100644 index 0000000..e12d606 --- /dev/null +++ b/sys/dev/mfi/mfi_linux.c @@ -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); +} diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c index 74491ed..f4e946d 100644 --- a/sys/dev/mfi/mfi_pci.c +++ b/sys/dev/mfi/mfi_pci.c @@ -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> diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h index faf83f7..597a0a7 100644 --- a/sys/dev/mfi/mfireg.h +++ b/sys/dev/mfi/mfireg.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 */ diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h index c02296d..b558365 100644 --- a/sys/dev/mfi/mfivar.h +++ b/sys/dev/mfi/mfivar.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; |