Add functionality and fix bugs so the driver will work with soon-to-be

released management apps.

1.  Implement poll().  This will check for queued aif's so that a
    subsequent ioctl call to retrieve the next aif will not block.
2.  Don't catch signals when sleeping on a fib sent from userland.  This
    causes a race and panic due to the pthread context switcher waking
    up the tsleep at inopportune times.
3.  Fix some whitespace nits.

MFC after:	3 days
This commit is contained in:
Scott Long 2001-12-02 03:47:33 +00:00
parent 2164257702
commit b3457b5173
7 changed files with 217 additions and 41 deletions

View file

@ -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;

View file

@ -213,7 +213,7 @@ aac_print_fib(struct aac_softc *sc, struct aac_fib *fib, char *caller)
fib->Header.StructType);
device_printf(sc->aac_dev, " Flags 0x%x\n", fib->Header.Flags);
device_printf(sc->aac_dev, " Size %d\n", fib->Header.Size);
device_printf(sc->aac_dev, " SenderSize %d\n",xi
device_printf(sc->aac_dev, " SenderSize %d\n",
fib->Header.SenderSize);
device_printf(sc->aac_dev, " SenderAddress 0x%x\n",
fib->Header.SenderFibAddress);
@ -225,7 +225,7 @@ aac_print_fib(struct aac_softc *sc, struct aac_fib *fib, char *caller)
case ContainerCommand:
{
struct aac_blockread *br;
struct aac_blockwrite *br;
struct aac_blockwrite *bw;
struct aac_sg_table *sg;
int i;

View file

@ -252,9 +252,9 @@ aac_disk_dump(dev_t dev)
for (i = 0; i < dumppages; ++i) {
vm_offset_t a = addr + (i * PAGE_SIZE);
if (is_physical_memory(a)) {
va = pmap_kenter_temporary(trunc_page(a), i);
va = pmap_kenter_temporary(trunc_page(a), i);
} else {
va = pmap_kenter_temporary(trunc_page(0), i);
va = pmap_kenter_temporary(trunc_page(0), i);
}
}

View file

@ -279,6 +279,10 @@ aac_pci_attach(device_t dev)
debug(2, "set hardware up for StrongARM");
sc->aac_if = aac_sa_interface;
break;
case AAC_HWIF_FALCON:
debug(2, "set hardware up for Falcon/PPC");
sc->aac_if = aac_fa_interface;
break;
}
break;
}

View file

@ -80,7 +80,7 @@ static struct aac_code_lookup aac_cpu_variant[] = {
{"i960HX", CPUI960_HX},
{"i960RX", CPUI960_RX},
{"StrongARM SA110", CPUARM_SA110},
{"PowerPC 603e", CPUPPC_603e},
{"MPC824x", CPUMPC_824x},
{"Unknown StrongARM", CPUARM_xxx},
{"Unknown PowerPC", CPUPPC_xxx},
{NULL, 0},
@ -111,6 +111,7 @@ static struct aac_code_lookup aac_container_types[] = {
{"RAID 00", CT_RAID00},
{"Volume of Mirrors", CT_VOLUME_OF_MIRRORS},
{"Pseudo RAID 3", CT_PSEUDO_RAID3},
{"RAID 50", CT_RAID50},
{NULL, 0},
{"unknown", 0}
};

View file

@ -305,6 +305,7 @@ typedef enum {
CT_RAID00, /* stripe of stripe */
CT_VOLUME_OF_MIRRORS, /* volume of mirror */
CT_PSEUDO_RAID3, /* really raid4 */
CT_RAID50, /* stripe of raid5 */
} AAC_FSAVolType;
/*
@ -421,7 +422,7 @@ typedef enum {
CPUI960_RX,
CPUARM_SA110,
CPUARM_xxx,
CPUPPC_603e,
CPUMPC_824x,
CPUPPC_xxx,
CPUSUBTYPE__last
} AAC_CpuSubType;
@ -1059,6 +1060,24 @@ struct aac_close_command {
u_int32_t ContainerId;
};
/*
* Register set for adapters based on the Falcon bridge and PPC core
*/
#define AAC_FA_DOORBELL0_CLEAR 0x00
#define AAC_FA_DOORBELL1_CLEAR 0x02
#define AAC_FA_DOORBELL0 0x04
#define AAC_FA_DOORBELL1 0x06
#define AAC_FA_MASK0_CLEAR 0x08
#define AAC_FA_MASK1_CLEAR 0x0a
#define AAC_FA_MASK0 0x0c
#define AAC_FA_MASK1 0x0e
#define AAC_FA_MAILBOX 0x10
#define AAC_FA_FWSTATUS 0x2c /* Mailbox 7 */
#define AAC_FA_INTSRC 0x900
#define AAC_FA_HACK(sc) (void)AAC_GETREG4(sc, AAC_FA_INTSRC)
/*
* Register definitions for the Adaptec AAC-364 'Jalapeno I/II' adapters, based
* on the SA110 'StrongArm'.
@ -1072,6 +1091,7 @@ struct aac_close_command {
#define AAC_SA_DOORBELL1_CLEAR 0x9a /* doorbell 1 (host->adapter) */
#define AAC_SA_DOORBELL1_SET 0x9e
#define AAC_SA_DOORBELL1 0x9e
#define AAC_SA_MASK1_CLEAR 0xa2
#define AAC_SA_MASK1_SET 0xa6
@ -1114,6 +1134,7 @@ struct aac_close_command {
* (ODBR and IDBR respectively for the i960Rx adapters)
*/
#define AAC_DB_PRINTF (1<<5) /* adapter requests host printf */
#define AAC_PRINTF_DONE (1<<5) /* Host completed printf processing */
/*
* Mask containing the interrupt bits we care about. We don't anticipate (or

View file

@ -208,7 +208,7 @@ struct aac_interface
int (*aif_get_fwstatus)(struct aac_softc *sc);
void (*aif_qnotify)(struct aac_softc *sc, int qbit);
int (*aif_get_istatus)(struct aac_softc *sc);
void (*aif_set_istatus)(struct aac_softc *sc, int mask);
void (*aif_clr_istatus)(struct aac_softc *sc, int mask);
void (*aif_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);
@ -217,11 +217,12 @@ struct aac_interface
};
extern struct aac_interface aac_rx_interface;
extern struct aac_interface aac_sa_interface;
extern struct aac_interface aac_fa_interface;
#define AAC_GET_FWSTATUS(sc) ((sc)->aac_if.aif_get_fwstatus((sc)))
#define AAC_QNOTIFY(sc, qbit) ((sc)->aac_if.aif_qnotify((sc), (qbit)))
#define AAC_GET_ISTATUS(sc) ((sc)->aac_if.aif_get_istatus((sc)))
#define AAC_CLEAR_ISTATUS(sc, mask) ((sc)->aac_if.aif_set_istatus((sc), \
#define AAC_CLEAR_ISTATUS(sc, mask) ((sc)->aac_if.aif_clr_istatus((sc), \
(mask)))
#define AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3) \
((sc)->aac_if.aif_set_mailbox((sc), (command), (arg0), (arg1), (arg2), \
@ -253,16 +254,18 @@ TAILQ_HEAD(aac_container_tq, aac_container);
#include <sys/lock.h>
#include <sys/mutex.h>
typedef struct mtx aac_lock_t;
#define AAC_LOCK_INIT(l) mtx_init(l, "AAC Container Mutex", MTX_DEF)
#define AAC_LOCK_INIT(l, s) mtx_init(l, s, MTX_DEF)
#define AAC_LOCK_AQUIRE(l) mtx_lock(l)
#define AAC_LOCK_RELEASE(l) mtx_unlock(l)
#else
typedef struct simplelock aac_lock_t;
#define AAC_LOCK_INIT(l) simple_lock_init(l)
#define AAC_LOCK_INIT(l, s) simple_lock_init(l)
#define AAC_LOCK_AQUIRE(l) simple_lock(l)
#define AAC_LOCK_RELEASE(l) simple_unlock(l)
#endif
#include <sys/selinfo.h>
/*
* Per-controller structure.
*/
@ -294,6 +297,7 @@ struct aac_softc
int aac_hwif;
#define AAC_HWIF_I960RX 0
#define AAC_HWIF_STRONGARM 1
#define AAC_HWIF_FALCON 2
#define AAC_HWIF_UNKNOWN -1
bus_dma_tag_t aac_common_dmat; /* common structure
* DMA tag */
@ -337,9 +341,11 @@ struct aac_softc
/* management interface */
dev_t aac_dev_t;
aac_lock_t aac_aifq_lock;
struct aac_aif_command aac_aifq[AAC_AIFQ_LENGTH];
int aac_aifq_head;
int aac_aifq_tail;
struct selinfo rcv_select;
struct proc *aifthread;
int aifflags;
#define AAC_AIFFLAGS_RUNNING (1 << 0)
@ -542,8 +548,8 @@ aac_dequeue_bio(struct aac_softc *sc)
s = splbio();
if ((bp = bioq_first(&sc->aac_bioq)) != NULL) {
bioq_remove(&sc->aac_bioq, bp);
AACQ_REMOVE(sc, AACQ_BIO);
bioq_remove(&sc->aac_bioq, bp);
AACQ_REMOVE(sc, AACQ_BIO);
}
splx(s);
return(bp);
@ -552,10 +558,11 @@ aac_dequeue_bio(struct aac_softc *sc)
static __inline void
aac_print_printf(struct aac_softc *sc)
{
if (sc->aac_common->ac_printf[0]) {
/*
* XXX We have the ability to read the length of the printf string
* from out of the mailboxes.
*/
device_printf(sc->aac_dev, "**Monitor** %.*s", AAC_PRINTF_BUFSIZE,
sc->aac_common->ac_printf);
sc->aac_common->ac_printf[0] = 0;
AAC_QNOTIFY(sc, AAC_DB_PRINTF);
}
}