summaryrefslogtreecommitdiffstats
path: root/sys/dev/aac/aac.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/aac/aac.c')
-rw-r--r--sys/dev/aac/aac.c195
1 files changed, 169 insertions, 26 deletions
diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c
index 4eef4e7..6a4948b 100644
--- a/sys/dev/aac/aac.c
+++ b/sys/dev/aac/aac.c
@@ -42,6 +42,8 @@
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/sysctl.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
#include <dev/aac/aac_compat.h>
@@ -109,6 +111,27 @@ static int aac_dequeue_fib(struct aac_softc *sc, int queue,
static int aac_enqueue_response(struct aac_softc *sc, int queue,
struct aac_fib *fib);
+/* Falcon/PPC interface */
+static int aac_fa_get_fwstatus(struct aac_softc *sc);
+static void aac_fa_qnotify(struct aac_softc *sc, int qbit);
+static int aac_fa_get_istatus(struct aac_softc *sc);
+static void aac_fa_clear_istatus(struct aac_softc *sc, int mask);
+static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
+ u_int32_t arg0, u_int32_t arg1,
+ u_int32_t arg2, u_int32_t arg3);
+static int aac_fa_get_mailboxstatus(struct aac_softc *sc);
+static void aac_fa_set_interrupts(struct aac_softc *sc, int enable);
+
+struct aac_interface aac_fa_interface = {
+ aac_fa_get_fwstatus,
+ aac_fa_qnotify,
+ aac_fa_get_istatus,
+ aac_fa_clear_istatus,
+ aac_fa_set_mailbox,
+ aac_fa_get_mailboxstatus,
+ aac_fa_set_interrupts
+};
+
/* StrongARM interface */
static int aac_sa_get_fwstatus(struct aac_softc *sc);
static void aac_sa_qnotify(struct aac_softc *sc, int qbit);
@@ -160,6 +183,7 @@ static char *aac_describe_code(struct aac_code_lookup *table,
static d_open_t aac_open;
static d_close_t aac_close;
static d_ioctl_t aac_ioctl;
+static d_poll_t aac_poll;
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);
@@ -176,7 +200,7 @@ static struct cdevsw aac_cdevsw = {
noread, /* read */
nowrite, /* write */
aac_ioctl, /* ioctl */
- nopoll, /* poll */
+ aac_poll, /* poll */
nommap, /* mmap */
nostrategy, /* strategy */
"aac", /* name */
@@ -251,7 +275,12 @@ aac_attach(struct aac_softc *sc)
* Register to probe our containers later.
*/
TAILQ_INIT(&sc->aac_container_tqh);
- AAC_LOCK_INIT(&sc->aac_container_lock);
+ AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
+
+ /*
+ * Lock for the AIF queue
+ */
+ AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
sc->aac_ich.ich_func = aac_startup;
sc->aac_ich.ich_arg = sc;
@@ -585,14 +614,10 @@ aac_intr(void *arg)
reason = AAC_GET_ISTATUS(sc);
- /* controller wants to talk to the log? Defer it to the AIF thread */
+ /* controller wants to talk to the log */
if (reason & AAC_DB_PRINTF) {
AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
- if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
- sc->aifflags |= AAC_AIFFLAGS_PENDING;
- wakeup(sc->aifthread);
- } else
- aac_print_printf(sc);
+ aac_print_printf(sc);
}
/* controller has a message for us? */
@@ -754,8 +779,6 @@ aac_host_command(struct aac_softc *sc)
fib);
}
}
- aac_print_printf(sc);
-
}
sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
wakeup(sc->aac_dev);
@@ -1063,6 +1086,15 @@ aac_dump_complete(struct aac_softc *sc)
/*
* Submit a command to the controller, return when it completes.
+ * XXX This is very dangerous! If the card has gone out to lunch, we could
+ * be stuck here forever. At the same time, signals are not caught
+ * because there is a risk that a signal could wakeup the tsleep before
+ * the card has a chance to complete the command. The passed in timeout
+ * is ignored for the same reason. Since there is no way to cancel a
+ * command in progress, we should probably create a 'dead' queue where
+ * commands go that have been interrupted/timed-out/etc, that keeps them
+ * out of the free pool. That way, if the card is just slow, it won't
+ * spam the memory of a command that has been recycled.
*/
static int
aac_wait_command(struct aac_command *cm, int timeout)
@@ -1077,9 +1109,7 @@ aac_wait_command(struct aac_command *cm, int timeout)
aac_startio(cm->cm_sc);
s = splbio();
while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
- error = tsleep(cm, PRIBIO | PCATCH, "aacwait", 0);
- if ((error == ERESTART) || (error == EINTR))
- break;
+ error = tsleep(cm, PRIBIO, "aacwait", 0);
}
splx(s);
return(error);
@@ -1856,6 +1886,17 @@ aac_rx_get_fwstatus(struct aac_softc *sc)
return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
}
+static int
+aac_fa_get_fwstatus(struct aac_softc *sc)
+{
+ int val;
+
+ debug_called(3);
+
+ val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
+ return (val);
+}
+
/*
* Notify the controller of a change in a given queue
*/
@@ -1876,6 +1917,15 @@ aac_rx_qnotify(struct aac_softc *sc, int qbit)
AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
}
+static void
+aac_fa_qnotify(struct aac_softc *sc, int qbit)
+{
+ debug_called(3);
+
+ AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
+ AAC_FA_HACK(sc);
+}
+
/*
* Get the interrupt reason bits
*/
@@ -1895,6 +1945,17 @@ aac_rx_get_istatus(struct aac_softc *sc)
return(AAC_GETREG4(sc, AAC_RX_ODBR));
}
+static int
+aac_fa_get_istatus(struct aac_softc *sc)
+{
+ int val;
+
+ debug_called(3);
+
+ val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
+ return (val);
+}
+
/*
* Clear some interrupt reason bits
*/
@@ -1914,6 +1975,15 @@ aac_rx_clear_istatus(struct aac_softc *sc, int mask)
AAC_SETREG4(sc, AAC_RX_ODBR, mask);
}
+static void
+aac_fa_clear_istatus(struct aac_softc *sc, int mask)
+{
+ debug_called(3);
+
+ AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
+ AAC_FA_HACK(sc);
+}
+
/*
* Populate the mailbox and set the command word
*/
@@ -1943,6 +2013,24 @@ aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
}
+static void
+aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
+ u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
+{
+ debug_called(4);
+
+ AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
+ AAC_FA_HACK(sc);
+}
+
/*
* Fetch the immediate command status word
*/
@@ -1962,6 +2050,17 @@ aac_rx_get_mailboxstatus(struct aac_softc *sc)
return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
}
+static int
+aac_fa_get_mailboxstatus(struct aac_softc *sc)
+{
+ int val;
+
+ debug_called(4);
+
+ val = AAC_GETREG4(sc, AAC_FA_MAILBOX);
+ return (val);
+}
+
/*
* Set/clear interrupt masks
*/
@@ -1989,6 +2088,20 @@ aac_rx_set_interrupts(struct aac_softc *sc, int enable)
}
}
+static void
+aac_fa_set_interrupts(struct aac_softc *sc, int enable)
+{
+ debug(2, "%sable interrupts", enable ? "en" : "dis");
+
+ if (enable) {
+ AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
+ AAC_FA_HACK(sc);
+ } else {
+ AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
+ AAC_FA_HACK(sc);
+ }
+}
+
/*
* Debugging and Diagnostics
*/
@@ -2133,7 +2246,7 @@ aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
break;
case FSACTL_OPEN_GET_ADAPTER_FIB:
arg = *(caddr_t*)arg;
- case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
+ case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
/*
* Pass the caller out an AdapterFibContext.
@@ -2183,13 +2296,37 @@ aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
error = 0;
break;
default:
- device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd);
+ debug(1, "unsupported cmd 0x%lx\n", cmd);
error = EINVAL;
break;
}
return(error);
}
+static int
+aac_poll(dev_t dev, int poll_events, struct thread *td)
+{
+ struct aac_softc *sc;
+ int revents;
+
+ sc = dev->si_drv1;
+ revents = 0;
+
+ AAC_LOCK_AQUIRE(&sc->aac_aifq_lock);
+ if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
+ if (sc->aac_aifq_tail != sc->aac_aifq_head)
+ revents |= poll_events & (POLLIN | POLLRDNORM);
+ }
+ AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
+
+ if (revents == 0) {
+ if (poll_events & (POLLIN | POLLRDNORM))
+ selrecord(td, &sc->rcv_select);
+ }
+
+ return (revents);
+}
+
/*
* Send a FIB supplied from userspace
*/
@@ -2231,8 +2368,10 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
/*
* Pass the FIB to the controller, wait for it to complete.
*/
- if ((error = aac_wait_command(cm, 30)) != 0) /* XXX user timeout? */
+ if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */
+ printf("aac_wait_command return %d\n", error);
goto out;
+ }
/*
* Copy the FIB and data back out to the caller.
@@ -2264,7 +2403,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
struct aac_mntinfo mi;
struct aac_mntinforesponse mir;
u_int16_t rsize;
- int next, s, found;
+ int next, found;
int added = 0, i = 0;
debug_called(2);
@@ -2385,15 +2524,19 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
}
/* Copy the AIF data to the AIF queue for ioctl retrieval */
- s = splbio();
+ AAC_LOCK_AQUIRE(&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;
- if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
- wakeup(sc->aac_aifq);
+ 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 */
+ selwakeup(&sc->rcv_select);
}
- splx(s);
+ AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
return;
}
@@ -2530,11 +2673,11 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
static int
aac_return_aif(struct aac_softc *sc, caddr_t uptr)
{
- int error, s;
+ int error;
debug_called(2);
- s = splbio();
+ AAC_LOCK_AQUIRE(&sc->aac_aifq_lock);
if (sc->aac_aifq_tail == sc->aac_aifq_head) {
error = EAGAIN;
} else {
@@ -2546,7 +2689,7 @@ aac_return_aif(struct aac_softc *sc, caddr_t uptr)
sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) %
AAC_AIFQ_LENGTH;
}
- splx(s);
+ AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
return(error);
}
@@ -2592,7 +2735,7 @@ aac_query_disk(struct aac_softc *sc, caddr_t uptr)
query_disk.Locked =
(disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
query_disk.Deleted = 0;
- query_disk.Bus = 0;
+ query_disk.Bus = device_get_unit(sc->aac_dev);
query_disk.Target = disk->unit;
query_disk.Lun = 0;
query_disk.UnMapped = 0;
OpenPOWER on IntegriCloud