Change the delivery mechanism for incoming target commands. We now

use a 256 entry ring buffer of descriptersfor this purpose.  This allows
the use of a simple 8bit counter in the sequencer code for tracking start
location.

Entries in the ring buffer now contain a "cmd_valid" byte at their tail.
As an entry is serviced, this byte is cleared by the kernel and set by
the sequencer during its dma of a new entry.  Since this byte is the last
portion of the command touched during a dma, the kernel can use this
byte to ensure the command it processes is completely valid.

The new command format requires a fixed sized DMA from the controller
to deliver which allowed for additional simplification of the sequencer
code.  The hack that required 1 SCB slot to be stolen for incoming
command delivery notification is also gone.
This commit is contained in:
Justin T. Gibbs 1998-11-23 01:33:47 +00:00
parent 9d2b090975
commit 08c6fbfa40
4 changed files with 99 additions and 83 deletions

View File

@ -36,7 +36,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.c,v 1.8 1998/10/15 18:21:47 gibbs Exp $
* $Id: aic7xxx.c,v 1.9 1998/10/15 23:49:27 gibbs Exp $
*/
/*
* A few notes on features of the driver.
@ -207,7 +207,8 @@ static void ahc_compile_devinfo(struct ahc_devinfo *devinfo,
u_int target, char channel);
static u_int ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev);
static void ahc_done(struct ahc_softc *ahc, struct scb *scbp);
static void ahc_handle_target_cmd(struct ahc_softc *ahc);
static void ahc_handle_target_cmd(struct ahc_softc *ahc,
struct target_cmd *cmd);
static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
static void ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat);
static void ahc_handle_reqinit(struct ahc_softc *ahc,
@ -989,12 +990,6 @@ ahc_intr(void *arg)
scb_index = ahc->qoutfifo[ahc->qoutfifonext];
ahc->qoutfifo[ahc->qoutfifonext++] = SCB_LIST_NULL;
if (scb_index == TARGET_CMD_CMPLT
&& (ahc->flags & AHC_TARGETMODE) != 0) {
ahc_handle_target_cmd(ahc);
continue;
}
scb = ahc->scb_data->scbarray[scb_index];
if (!scb || !(scb->flags & SCB_ACTIVE)) {
printf("%s: WARNING no command for scb %d "
@ -1012,6 +1007,16 @@ ahc_intr(void *arg)
ahc_calc_residual(scb);
ahc_done(ahc, scb);
}
if ((ahc->flags & AHC_TARGETMODE) != 0) {
while (ahc->targetcmds[ahc->tqinfifonext].cmd_valid) {
struct target_cmd *cmd;
cmd = &ahc->targetcmds[ahc->tqinfifonext++];
ahc_handle_target_cmd(ahc, cmd);
cmd->cmd_valid = 0;
}
}
}
if (intstat & BRKADRINT) {
/*
@ -1041,23 +1046,17 @@ ahc_intr(void *arg)
}
static void
ahc_handle_target_cmd(struct ahc_softc *ahc)
ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
{
struct tmode_tstate *tstate;
struct tmode_lstate *lstate;
struct ccb_accept_tio *atio;
struct target_cmd *cmd;
u_int8_t *byte;
int initiator;
int target;
int lun;
cmd = &ahc->targetcmds[ahc->next_targetcmd];
ahc->next_targetcmd++;
if (ahc->next_targetcmd >= ahc->num_targetcmds)
ahc->next_targetcmd = 0;
initiator = cmd->icl >> 4;
initiator = cmd->initiator_channel >> 4;
target = cmd->targ_id;
lun = (cmd->identify & MSG_IDENTIFY_LUNMASK);
@ -2535,18 +2534,10 @@ ahc_init(struct ahc_softc *ahc)
if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) {
ahc->flags |= AHC_PAGESCBS;
ahc->scb_data->maxscbs = AHC_SCB_MAX;
if ((ahc->flags & AHC_TARGETMODE) != 0) {
/* Steal one slot for TMODE commands */
ahc->scb_data->maxscbs--;
}
printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs,
ahc->scb_data->maxscbs);
} else {
ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs;
if ((ahc->flags & AHC_TARGETMODE) != 0) {
/* Steal one slot for TMODE commands */
ahc->scb_data->maxscbs--;
}
ahc->flags &= ~AHC_PAGESCBS;
printf("%d SCBs\n", ahc->scb_data->maxhscbs);
}
@ -2761,9 +2752,10 @@ ahc_init(struct ahc_softc *ahc)
if ((ahc->flags & AHC_TARGETMODE) != 0) {
size_t array_size;
ahc->num_targetcmds = 32;
array_size = ahc->num_targetcmds * sizeof(struct target_cmd);
ahc->targetcmds = malloc(array_size, M_DEVBUF, M_NOWAIT);
array_size = AHC_TMODE_CMDS * sizeof(struct target_cmd);
ahc->targetcmds = contigmalloc(array_size, M_DEVBUF,
M_NOWAIT, 0ul, 0xffffffff,
PAGE_SIZE, 0x10000);
if (ahc->targetcmds == NULL) {
printf("%s: unable to allocate targetcmd array. "
@ -2771,8 +2763,11 @@ ahc_init(struct ahc_softc *ahc)
return (-1);
}
bzero(ahc->targetcmds, array_size);
ahc_outb(ahc, TMODE_CMDADDR_NEXT, 0);
/* All target command blocks start out invalid. */
for (i = 0; i < AHC_TMODE_CMDS; i++)
ahc->targetcmds[i].cmd_valid = 0;
ahc_outb(ahc, KERNEL_TQINPOS, 0);
ahc_outb(ahc, TQINPOS, 0);
}
/*
@ -3811,7 +3806,10 @@ ahc_loadseq(struct ahc_softc *ahc)
u_int8_t download_consts[4];
/* Setup downloadable constant table */
#if 0
/* No downloaded constants are currently defined. */
download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds;
#endif
cur_patch = patches;
downloaded = 0;
@ -4812,9 +4810,9 @@ ahc_dump_targcmd(struct target_cmd *cmd)
u_int8_t *last_byte;
int i;
byte = &cmd->icl;
byte = &cmd->initiator_channel;
/* Debugging info for received commands */
last_byte = &cmd[1].icl;
last_byte = &cmd[1].initiator_channel;
i = 0;
while (byte < last_byte) {

View File

@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.h,v 1.40 1997/02/25 03:05:35 gibbs Exp $
* $Id: aic7xxx.h,v 1.1 1998/09/15 07:24:16 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@ -68,6 +68,12 @@
* aic7850 has only 3.
*/
#define AHC_TMODE_CMDS 256 /*
* Ring Buffer of incoming target commands.
* We allocate 256 to simplify the logic
* in the sequencer by using the natural
* wrap point of an 8bit counter.
*/
#if defined(__FreeBSD__)
extern u_long ahc_unit;
@ -247,13 +253,17 @@ struct scb_data {
* Connection desciptor for select-in requests in target mode.
* The first byte is the connecting target, followed by identify
* message and optional tag information, terminated by 0xFF. The
* remainder is the command to execute.
* remainder is the command to execute. The cmd_valid byte is on
* an 8 byte boundary to simplify setting it on aic7880 hardware
* which only has limited direct access to the DMA FIFO.
*/
struct target_cmd {
u_int8_t icl; /* Really only holds Initiator ID */
u_int8_t targ_id; /* Target ID we were selected at */
u_int8_t identify; /* Identify message */
u_int8_t bytes[29];
u_int8_t initiator_channel;
u_int8_t targ_id; /* Target ID we were selected at */
u_int8_t identify; /* Identify message */
u_int8_t bytes[21];
u_int8_t cmd_valid;
u_int8_t pad[7];
};
/*
@ -462,10 +472,11 @@ struct ahc_softc {
int unsolicited_ints;
pcici_t pci_config_id;
/* Hmmm. */
/*
* Target incoming command FIFO.
*/
struct target_cmd *targetcmds;
int next_targetcmd;
int num_targetcmds;
u_int8_t tqinfifonext;
/*
* Incoming and outgoing message handling.

View File

@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
* $Id: aic7xxx.reg,v 1.7 1998/09/15 07:24:16 gibbs Exp $
*/
/*
@ -763,6 +763,16 @@ register DFSTATUS {
bit FIFOEMP 0x01
}
register DFWADDR {
address 0x95
access_mode RW
}
register DFRADDR {
address 0x97
access_mode RW
}
register DFDAT {
address 0x099
access_mode RW
@ -1255,10 +1265,14 @@ scratch_ram {
size 1
}
/*
* Offset into the command descriptor array for the next
* available desciptor to use.
* Kernel and sequencer offsets into the queue of
* incoming target mode command descriptors. The
* queue is full when the ((KERNEL_TQINPOS - TQINPOS) == 1)
*/
TMODE_CMDADDR_NEXT {
KERNEL_TQINPOS {
size 1
}
TQINPOS {
size 1
}
ARG_1 {
@ -1360,5 +1374,7 @@ const CMD_GROUP5_BYTE_DELTA 11
/*
* Number of command descriptors in the command descriptor array.
*/
* No longer used, but left here as an example for how downloaded
* constantants can be defined.
const TMODE_NUMCMDS download
*/

View File

@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.seq,v 1.78 1998/09/15 07:24:16 gibbs Exp $
* $Id: aic7xxx.seq,v 1.79 1998/09/21 16:46:13 gibbs Exp $
*/
#include <dev/aic7xxx/aic7xxx.reg>
@ -234,11 +234,12 @@ select_in:
/*
* Setup the DMA for sending the identify and
* command information. We keep a count of the
* number of bytes to send to the host in ARG_2.
* command information.
*/
or SEQ_FLAGS, CMDPHASE_PENDING;
mov A, TMODE_CMDADDR_NEXT;
/* XXX If ring buffer is full, return busy or queue full */
mov A, TQINPOS;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi DINDEX, CCHADDR;
mvi TMODE_CMDADDR call set_32byte_addr;
@ -289,6 +290,7 @@ select_in:
* Our first message must be one of IDENTIFY, ABORT, or
* BUS_DEVICE_RESET.
*/
/* XXX May need to be more lax here for older initiators... */
test DINDEX, MSG_IDENTIFYFLAG jz more_first_messages;
/* Store for host */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@ -296,7 +298,6 @@ select_in:
} else {
mov DFDAT, DINDEX;
}
mvi ARG_2, 3;
/* Remember for disconnection decision */
test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
@ -337,7 +338,6 @@ select_in:
} else {
mov DFDAT, DINDEX;
}
add ARG_2, 2;
jmp ident_messages_done;
more_first_messages:
@ -483,17 +483,6 @@ target_busfree:
jmp poll_for_work;
target_cmdphase:
/*
* Add one for the terminating byte
* and one for the command code.
*/
if ((ahc->features & AHC_CMD_CHAN) != 0) {
add CCHCNT, 2, ARG_2;
} else {
add HCNT[0], 2, ARG_2;
clr HCNT[1];
clr HCNT[2];
}
mvi SCSISIGO, P_COMMAND|BSYO;
call targ_inb;
mov A, DINDEX;
@ -506,20 +495,16 @@ target_cmdphase:
/*
* Determine the number of bytes to read
* based on the command group code using an adding
* jump table. Count is one less than the total
* since we've already fetched the first byte.
* based on the command group code via table lookup.
* We reuse the first 8 bytes of the TARG_SCSIRATE
* BIOS array for this table. Count is one less than
* the total for the command since we've already fetched
* the first byte.
*/
shr A, CMD_GROUP_CODE_SHIFT;
add SINDEX, TARG_SCSIRATE, A;
mov A, SINDIR;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
add CCHCNT, A;
} else {
add HCNT[0], A;
}
test A, 0xFF jz command_phase_done;
command_loop:
or SXFRCTL0, SPIOEN;
@ -566,17 +551,28 @@ complete_target_cmd:
test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2;
mov SCB_TAG jmp complete_post;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
/* Set the valid byte */
mvi CCSCBADDR, 24;
mov CCSCBRAM, ALLONES;
mvi CCHCNT, 28;
or CCSCBCTL, CCSCBEN|CCSCBRESET;
test CCSCBCTL, CCSCBDONE jz .;
clr CCSCBCTL;
} else {
/* Set the valid byte */
or DFCNTRL, FIFORESET;
mvi DFWADDR, 3; /* Third 64bit word or byte 24 */
mov DFDAT, ALLONES;
mvi HCNT[0], 28;
clr HCNT[1];
clr HCNT[2];
or DFCNTRL, HDMAEN|FIFOFLUSH;
call dma_finish;
}
inc TMODE_CMDADDR_NEXT;
cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
clr TMODE_CMDADDR_NEXT;
mvi TARGET_CMD_CMPLT jmp complete_post;
inc TQINPOS;
test SEQ_FLAGS, NO_DISCONNECT jz . + 2;
mvi INTSTAT,TARGET_SYNC_CMD|CMDCMPLT ret;
mvi INTSTAT,CMDCMPLT ret;
}
initiator_select:
mvi SPIOEN call initialize_channel;
@ -960,11 +956,7 @@ p_mesgout:
mov SINDEX, MSG_OUT;
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
p_mesgout_identify:
if ((ahc->features & AHC_WIDE) != 0) {
and SINDEX,0xf,SCB_TCL; /* lun */
} else {
and SINDEX,0x7,SCB_TCL; /* lun */
}
and SINDEX,LID,SCB_TCL; /* lun */
and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
or SINDEX,A; /* or in disconnect privledge */
or SINDEX,MSG_IDENTIFYFLAG;
@ -1122,9 +1114,8 @@ complete_post:
inc QOUTPOS;
}
if ((ahc->flags & AHC_TARGETMODE) != 0) {
test SEQ_FLAGS, NO_DISCONNECT jz . + 3;
mvi INTSTAT,TARGET_SYNC_CMD|CMDCMPLT;
ret;
test SEQ_FLAGS, NO_DISCONNECT jz . + 2;
mvi INTSTAT,TARGET_SYNC_CMD|CMDCMPLT ret;
}
mvi INTSTAT,CMDCMPLT ret;