diff options
author | jhb <jhb@FreeBSD.org> | 2008-06-26 22:33:24 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-06-26 22:33:24 +0000 |
commit | 03cd96cc3811dad6aa07fa8afb3e5ae40bf13296 (patch) | |
tree | 93cbe7c2a1e5a33d877393d03719bbfe12a4e155 /sys/dev | |
parent | ed08bd0d6d114e86dc18fe9c793810ffc35cf3ea (diff) | |
download | FreeBSD-src-03cd96cc3811dad6aa07fa8afb3e5ae40bf13296.zip FreeBSD-src-03cd96cc3811dad6aa07fa8afb3e5ae40bf13296.tar.gz |
Adjust the handling of pending log events during boot:
- Fetch events from the controller in batches of 15 rather than a single
event at a time.
- When fetching events from the controller, honor the event class and
locale settings (via hw.mfi tunables). This also allows the firmware to
skip over unwanted log entries resulting in fewer requests to the
controller if there many unwanted log entries since the last clean
shutdown.
- Don't drop the driver mutex while decoding an event.
- If we get an error other than MFI_STAT_NOT_FOUND (basically EOF for
hitting the end of the event log) then emit a warning and bail on
processing further log entries.
Reviewed by: ambrisko, scottl
MFC after: 2 weeks
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/mfi/mfi.c | 125 |
1 files changed, 75 insertions, 50 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index 69125ef..cf97674 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -86,7 +86,7 @@ static int mfi_wait_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 int mfi_parse_entries(struct mfi_softc *, int, int); static int mfi_dcmd_command(struct mfi_softc *, struct mfi_command **, uint32_t, void **, size_t); static void mfi_data_cb(void *, bus_dma_segment_t *, int, int); @@ -785,12 +785,14 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) free(log_state, M_MFIBUF); return (error); } - /* The message log is a circular buffer */ - for (seq = log_state->shutdown_seq_num; - seq != log_state->newest_seq_num; seq++) { - mfi_get_entry(sc, seq); - } - mfi_get_entry(sc, seq); + + /* + * Walk through any events that fired since the last + * shutdown. + */ + mfi_parse_entries(sc, log_state->shutdown_seq_num, + log_state->newest_seq_num); + seq = log_state->newest_seq_num; } else seq = seq_start; mfi_aen_register(sc, seq, class_locale.word); @@ -1384,9 +1386,7 @@ mfi_aen_complete(struct mfi_command *cm) * XXX If this function is too expensive or is recursive, then * events should be put onto a queue and processed later. */ - mtx_unlock(&sc->mfi_io_lock); mfi_decode_evt(sc, detail); - mtx_lock(&sc->mfi_io_lock); seq = detail->seq + 1; TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, @@ -1409,66 +1409,91 @@ mfi_aen_complete(struct mfi_command *cm) } } -/* Only do one event for now so we can easily iterate through them */ -#define MAX_EVENTS 1 +#define MAX_EVENTS 15 + static int -mfi_get_entry(struct mfi_softc *sc, int seq) +mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) { struct mfi_command *cm; struct mfi_dcmd_frame *dcmd; struct mfi_evt_list *el; - int error; - int i; - int size; + union mfi_evt class_locale; + int error, i, seq, size; - if ((cm = mfi_dequeue_free(sc)) == NULL) { - return (EBUSY); - } + class_locale.members.reserved = 0; + class_locale.members.locale = mfi_event_locale; + class_locale.members.class = mfi_event_class; size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * (MAX_EVENTS - 1); el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); - if (el == NULL) { - mfi_release_command(cm); + if (el == NULL) 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 = size; - 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 = el; - cm->cm_len = size; + for (seq = start_seq;;) { + if ((cm = mfi_dequeue_free(sc)) == NULL) { + free(el, M_MFIBUF); + return (EBUSY); + } - if ((error = mfi_mapcmd(sc, cm)) != 0) { - device_printf(sc->mfi_dev, "Failed to get controller entry\n"); - sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / - MFI_SECTOR_LEN; - free(el, M_MFIBUF); - mfi_release_command(cm); - return (0); - } + 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 = size; + dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; + ((uint32_t *)&dcmd->mbox)[0] = seq; + ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; + 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 = el; + cm->cm_len = size; + + if ((error = mfi_mapcmd(sc, cm)) != 0) { + device_printf(sc->mfi_dev, + "Failed to get controller entries\n"); + mfi_release_command(cm); + break; + } - bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); + bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); + + if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { + mfi_release_command(cm); + break; + } + if (dcmd->header.cmd_status != MFI_STAT_OK) { + device_printf(sc->mfi_dev, + "Error %d fetching controller entries\n", + dcmd->header.cmd_status); + mfi_release_command(cm); + break; + } + mfi_release_command(cm); - if (dcmd->header.cmd_status != MFI_STAT_NOT_FOUND) { for (i = 0; i < el->count; i++) { - if (seq + i == el->event[i].seq) - mfi_decode_evt(sc, &el->event[i]); + /* + * If this event is newer than 'stop_seq' then + * break out of the loop. Note that the log + * is a circular buffer so we have to handle + * the case that our stop point is earlier in + * the buffer than our start point. + */ + if (el->event[i].seq >= stop_seq) { + if (start_seq <= stop_seq) + break; + else if (el->event[i].seq < start_seq) + break; + } + mfi_decode_evt(sc, &el->event[i]); } + seq = el->event[el->count - 1].seq + 1; } - free(cm->cm_data, M_MFIBUF); - mfi_release_command(cm); + free(el, M_MFIBUF); return (0); } |