summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2007-12-07 00:22:23 +0000
committeremaste <emaste@FreeBSD.org>2007-12-07 00:22:23 +0000
commite85902857b909623d774f2b8773d681b4116c23a (patch)
treecf73a829fbbb71d89224d2f81264805130bd2150 /sys
parente93a39275f61f4da8f8f1fb792c32f91d727d7f1 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/aac/aac.c206
-rw-r--r--sys/dev/aac/aacvar.h20
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;
OpenPOWER on IntegriCloud