diff options
author | emaste <emaste@FreeBSD.org> | 2007-12-07 00:22:23 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2007-12-07 00:22:23 +0000 |
commit | e85902857b909623d774f2b8773d681b4116c23a (patch) | |
tree | cf73a829fbbb71d89224d2f81264805130bd2150 /sys/dev/aac | |
parent | e93a39275f61f4da8f8f1fb792c32f91d727d7f1 (diff) | |
download | FreeBSD-src-e85902857b909623d774f2b8773d681b4116c23a.zip FreeBSD-src-e85902857b909623d774f2b8773d681b4116c23a.tar.gz |
Allow simultaneous opens of the device for issuing commands to the
controller. This is merged from Adaptec driver build 11669.
Diffstat (limited to 'sys/dev/aac')
-rw-r--r-- | sys/dev/aac/aac.c | 206 | ||||
-rw-r--r-- | sys/dev/aac/aacvar.h | 20 |
2 files changed, 151 insertions, 75 deletions
diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c index e62bd47..cbb5963 100644 --- a/sys/dev/aac/aac.c +++ b/sys/dev/aac/aac.c @@ -216,8 +216,11 @@ static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); static void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); static int aac_rev_check(struct aac_softc *sc, caddr_t udata); +static int aac_open_aif(struct aac_softc *sc, caddr_t arg); +static int aac_close_aif(struct aac_softc *sc, caddr_t arg); static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); -static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); +static int aac_return_aif(struct aac_softc *sc, + struct aac_fib_context *ctx, caddr_t uptr); static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); static void aac_ioctl_event(struct aac_softc *sc, @@ -283,9 +286,6 @@ aac_attach(struct aac_softc *sc) TAILQ_INIT(&sc->aac_container_tqh); TAILQ_INIT(&sc->aac_ev_cmfree); - /* Initialize the local AIF queue pointers */ - sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; - /* * Initialise the adapter. */ @@ -2824,11 +2824,7 @@ aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) debug_called(2); sc = dev->si_drv1; - - /* Check to make sure the device isn't already open */ - if (sc->aac_state & AAC_STATE_OPEN) { - return EBUSY; - } + sc->aac_open_cnt++; sc->aac_state |= AAC_STATE_OPEN; return 0; @@ -2842,9 +2838,10 @@ aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) debug_called(2); sc = dev->si_drv1; - + sc->aac_open_cnt--; /* Mark this unit as no longer open */ - sc->aac_state &= ~AAC_STATE_OPEN; + if (sc->aac_open_cnt == 0) + sc->aac_state &= ~AAC_STATE_OPEN; return 0; } @@ -2855,7 +2852,6 @@ aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) union aac_statrequest *as; struct aac_softc *sc; int error = 0; - uint32_t cookie; debug_called(2); @@ -2893,20 +2889,7 @@ aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) arg = *(caddr_t*)arg; case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); - /* - * Pass the caller out an AdapterFibContext. - * - * Note that because we only support one opener, we - * basically ignore this. Set the caller's context to a magic - * number just in case. - * - * The Linux code hands the driver a pointer into kernel space, - * and then trusts it when the caller hands it back. Aiee! - * Here, we give it the proc pointer of the per-adapter aif - * thread. It's only used as a sanity check in other calls. - */ - cookie = (uint32_t)(uintptr_t)sc->aifthread; - error = copyout(&cookie, arg, sizeof(cookie)); + error = aac_open_aif(sc, arg); break; case FSACTL_GET_NEXT_ADAPTER_FIB: arg = *(caddr_t*)arg; @@ -2915,9 +2898,10 @@ aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) error = aac_getnext_aif(sc, arg); break; case FSACTL_CLOSE_GET_ADAPTER_FIB: + arg = *(caddr_t*)arg; case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); - /* don't do anything here */ + error = aac_close_aif(sc, arg); break; case FSACTL_MINIPORT_REV_CHECK: arg = *(caddr_t*)arg; @@ -2965,7 +2949,7 @@ aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) mtx_lock(&sc->aac_aifq_lock); if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { - if (sc->aac_aifq_tail != sc->aac_aifq_head) + if (sc->aifq_idx != 0 || sc->aifq_filled) revents |= poll_events & (POLLIN | POLLRDNORM); } mtx_unlock(&sc->aac_aifq_lock); @@ -3091,10 +3075,11 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) { struct aac_aif_command *aif; struct aac_container *co, *co_next; + struct aac_fib_context *ctx; struct aac_mntinfo *mi; struct aac_mntinforesp *mir = NULL; u_int16_t rsize; - int next, found; + int next, current, found; int count = 0, added = 0, i = 0; debug_called(2); @@ -3225,17 +3210,26 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) /* Copy the AIF data to the AIF queue for ioctl retrieval */ mtx_lock(&sc->aac_aifq_lock); - next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; - if (next != sc->aac_aifq_tail) { - bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); - sc->aac_aifq_head = next; - - /* On the off chance that someone is sleeping for an aif... */ - if (sc->aac_state & AAC_STATE_AIF_SLEEPER) - wakeup(sc->aac_aifq); - /* Wakeup any poll()ers */ - selwakeuppri(&sc->rcv_select, PRIBIO); - } + current = sc->aifq_idx; + next = (current + 1) % AAC_AIFQ_LENGTH; + if (next == 0) + sc->aifq_filled = 1; + bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); + /* modify AIF contexts */ + if (sc->aifq_filled) { + for (ctx = sc->fibctx; ctx; ctx = ctx->next) { + if (next == ctx->ctx_idx) + ctx->ctx_wrap = 1; + else if (current == ctx->ctx_idx && ctx->ctx_wrap) + ctx->ctx_idx = next; + } + } + sc->aifq_idx = next; + /* On the off chance that someone is sleeping for an aif... */ + if (sc->aac_state & AAC_STATE_AIF_SLEEPER) + wakeup(sc->aac_aifq); + /* Wakeup any poll()ers */ + selwakeuppri(&sc->rcv_select, PRIBIO); mtx_unlock(&sc->aac_aifq_lock); return; @@ -3281,36 +3275,111 @@ aac_rev_check(struct aac_softc *sc, caddr_t udata) } /* + * Pass the fib context to the caller + */ +static int +aac_open_aif(struct aac_softc *sc, caddr_t arg) +{ + struct aac_fib_context *fibctx, *ctx; + int error = 0; + + debug_called(2); + + fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); + if (fibctx == NULL) + return (ENOMEM); + + mtx_lock(&sc->aac_aifq_lock); + /* all elements are already 0, add to queue */ + if (sc->fibctx == NULL) + sc->fibctx = fibctx; + else { + for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) + ; + ctx->next = fibctx; + fibctx->prev = ctx; + } + + /* evaluate unique value */ + fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); + ctx = sc->fibctx; + while (ctx != fibctx) { + if (ctx->unique == fibctx->unique) { + fibctx->unique++; + ctx = sc->fibctx; + } else { + ctx = ctx->next; + } + } + mtx_unlock(&sc->aac_aifq_lock); + + error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); + if (error) + aac_close_aif(sc, (caddr_t)ctx); + return error; +} + +/* + * Close the caller's fib context + */ +static int +aac_close_aif(struct aac_softc *sc, caddr_t arg) +{ + struct aac_fib_context *ctx; + + debug_called(2); + + mtx_lock(&sc->aac_aifq_lock); + for (ctx = sc->fibctx; ctx; ctx = ctx->next) { + if (ctx->unique == *(uint32_t *)&arg) { + if (ctx == sc->fibctx) + sc->fibctx = NULL; + else { + ctx->prev->next = ctx->next; + if (ctx->next) + ctx->next->prev = ctx->prev; + } + break; + } + } + mtx_unlock(&sc->aac_aifq_lock); + if (ctx) + free(ctx, M_AACBUF); + + return 0; +} + +/* * Pass the caller the next AIF in their queue */ static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg) { struct get_adapter_fib_ioctl agf; + struct aac_fib_context *ctx; int error; debug_called(2); if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { - - /* - * Check the magic number that we gave the caller. - */ - if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { - error = EFAULT; - } else { - error = aac_return_aif(sc, agf.AifFib); - if ((error == EAGAIN) && (agf.Wait)) { - sc->aac_state |= AAC_STATE_AIF_SLEEPER; - while (error == EAGAIN) { - error = tsleep(sc->aac_aifq, PRIBIO | - PCATCH, "aacaif", 0); - if (error == 0) - error = aac_return_aif(sc, - agf.AifFib); - } - sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; + for (ctx = sc->fibctx; ctx; ctx = ctx->next) { + if (agf.AdapterFibContext == ctx->unique) + break; + } + if (!ctx) + return (EFAULT); + + error = aac_return_aif(sc, ctx, agf.AifFib); + if (error == EAGAIN && agf.Wait) { + debug(2, "aac_getnext_aif(): waiting for AIF"); + sc->aac_state |= AAC_STATE_AIF_SLEEPER; + while (error == EAGAIN) { + error = tsleep(sc->aac_aifq, PRIBIO | + PCATCH, "aacaif", 0); + if (error == 0) + error = aac_return_aif(sc, ctx, agf.AifFib); } + sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; } } return(error); @@ -3320,27 +3389,28 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg) * Hand the next AIF off the top of the queue out to userspace. */ static int -aac_return_aif(struct aac_softc *sc, caddr_t uptr) +aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) { - int next, error; + int current, error; debug_called(2); mtx_lock(&sc->aac_aifq_lock); - if (sc->aac_aifq_tail == sc->aac_aifq_head) { + current = ctx->ctx_idx; + if (current == sc->aifq_idx && !ctx->ctx_wrap) { + /* empty */ mtx_unlock(&sc->aac_aifq_lock); return (EAGAIN); } - - next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; - error = copyout(&sc->aac_aifq[next], uptr, - sizeof(struct aac_aif_command)); + error = + copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); if (error) device_printf(sc->aac_dev, "aac_return_aif: copyout returned %d\n", error); - else - sc->aac_aifq_tail = next; - + else { + ctx->ctx_wrap = 0; + ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; + } mtx_unlock(&sc->aac_aifq_lock); return(error); } diff --git a/sys/dev/aac/aacvar.h b/sys/dev/aac/aacvar.h index de3425b..cce57de 100644 --- a/sys/dev/aac/aacvar.h +++ b/sys/dev/aac/aacvar.h @@ -272,6 +272,14 @@ extern struct aac_interface aac_rkt_interface; #define AAC_GETREG1(sc, reg) bus_space_read_1 (sc->aac_btag, \ sc->aac_bhandle, reg) +/* fib context (IOCTL) */ +struct aac_fib_context { + u_int32_t unique; + int ctx_idx; + int ctx_wrap; + struct aac_fib_context *next, *prev; +}; + /* * Per-controller structure. */ @@ -298,6 +306,7 @@ struct aac_softc #define AAC_STATE_OPEN (1<<1) #define AAC_STATE_INTERRUPTS_ON (1<<2) #define AAC_STATE_AIF_SLEEPER (1<<3) + int aac_open_cnt; struct FsaRevision aac_revision; /* controller hardware interface */ @@ -327,10 +336,6 @@ struct aac_softc TAILQ_HEAD(,aac_command) aac_ready; /* commands on hold for * controller resources */ TAILQ_HEAD(,aac_command) aac_busy; - TAILQ_HEAD(,aac_command) aac_aif; -#if 0 - TAILQ_HEAD(,aac_command) aac_norm; -#endif TAILQ_HEAD(,aac_event) aac_ev_cmfree; struct bio_queue_head aac_bioq; struct aac_queue_table *aac_queues; @@ -356,9 +361,10 @@ struct aac_softc /* management interface */ struct cdev *aac_dev_t; struct mtx aac_aifq_lock; - struct aac_aif_command aac_aifq[AAC_AIFQ_LENGTH]; - int aac_aifq_head; - int aac_aifq_tail; + struct aac_fib aac_aifq[AAC_AIFQ_LENGTH]; + int aifq_idx; + int aifq_filled; + struct aac_fib_context *fibctx; struct selinfo rcv_select; struct proc *aifthread; int aifflags; |