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:
parent
0b3bd2def8
commit
ad7080d581
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user