Upgrade to version 1.1 of the aic79xx U320 driver.

aic79xx.c:
	o Remove redundant ahd_update_modes() call.
	o Correct panic in diagnostic should state corruption cause
	  the SCB Id to be invalid during a selection timeout.
	o Add workaround for missing BUSFREEREV feature in Rev A silicon.
	o Corect formatting nits.
	o Use register pretty printing in more places.
	o Save and restore our SCB pointer when updating the waiting queue
	  list for an "expected" LQ-out busfree.
	o In ahd_clear_intstat, deal with the missing autoclear in the
	  CLRLQO* registers.
	o BE fixup in a diagnostic printf.
	o Make sure that we are in the proper mode before disabling
	  selections in ahd_update_pending_scbs.
	o Add more diagnostics.
	o task_attribute_nonpkt_tag -> task_attribute: we don't need a
	  nonpkt_tag field anymore for allowing all 512 SCBs to be
	  used in non-packetized connections.
	o Negotiate HOLD_MCS to U320 devices.
	o Add a few additional mode assertions.
	o Restore the chip mode after clearing out the qinfifo so that
	  code using ahd_abort_scbs sees a consistent mode.
	o Simplify the DMA engine shutdown routine prior to performing
	  a bus reset.
	o Perform the sequencer restart after a chip reset prior to
	  setting up our timer to poll for the reset to be complete.
	  On some OSes, the timer could actually pre-empt us and order
	  is important here.
	o Have our "reset poller" set the expected mode since there is
	  no guarantee of what mode will be in force when we are called
	  from the OS timer.
	o Save and restore the SCB pointer in ahd_dump_card_state().  This
	  routine must not modify card state.
	o Ditto for ahd_dump_scbs().

aic79xx.h:
	o Add a few more chip bug definitions.
	o Align our tag on a 32bit boundary.

aic79xx.reg:
aic79xx.seq:
	o Start work on removing workarounds for Rev B.
	o Use a special location in scratch from for stroring
	  our SCBPTR during legacy FIFO allocations.  This corrects
	  problems in mixed packetized/non-packetized configurations
	  where calling into a FIFO task corrupted our SCBPTR.
	o Don't rely on DMA priority to guarantee that all data in
	  our FIFOs will flush prior to a command completion notification
	  going out of the command channel.  We've never seen this assumption
	  fail, but better safe than sorry.
	o Deal with missing BUSFREEREV feature in H2A.
	o Simplify disconnect list code now that the list will always
	  have only a single entry.
	o Implement the AHD_REG_SLOW_SETTLE_BUG workaround.
	o Swith to using "REG_ISR" for local mode scratch during
	  our ISR.
	o Add a missing jmp to the data_group_dma_loop after our
	  data pointers have been re-initialized by the kernel.
	o Correct test in the bitbucket code so that we actually
	  wait for the bitbucket to complete before signaling the
	  kernel of the overrun condition.
	o Reposition pkt_saveptrs to avoid a jmp instruction.
	o Update a comment to reflect that the code now waits for
	  a FIFO to drain prior to issuing a CLRCHN.

aic79xx_inline.h:
	o Remove unused untagged queue handling code.
	o Don't attempt to htole64 what could be a 32bit value.

aic79xx_pci.c:
	o Set additional bug flags for rev A chips.
This commit is contained in:
Justin T. Gibbs 2002-09-26 22:54:00 +00:00
parent 0889fb1da5
commit c59c8a72cf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=104023
6 changed files with 335 additions and 243 deletions

View File

@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#102 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#113 $
*
* $FreeBSD$
*/
@ -488,7 +488,6 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
struct scb *scb;
u_int scbid;
ahd_update_modes(ahd);
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
@ -933,12 +932,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_outb(ahd, CLRSINT0, CLRSELINGO);
scbid = ahd_inw(ahd, WAITING_TID_HEAD);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
ahd_print_path(ahd, scb);
printf("Saw Selection Timeout for SCB 0x%x\n", scbid);
}
#endif
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
printf("%s: ahd_intr - referenced scb not "
@ -947,6 +940,13 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_dump_card_state(ahd);
panic("For diagnostics");
} else {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
ahd_print_path(ahd, scb);
printf("Saw Selection Timeout for SCB 0x%x\n",
scbid);
}
#endif
ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahd_freeze_devq(ahd, scb);
}
@ -1033,22 +1033,31 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) {
restart = ahd_handle_pkt_busfree(ahd, busfreetime);
} else {
packetized = 0;
restart = ahd_handle_nonpkt_busfree(ahd);
}
/*
* Clear the busfree interrupt status. The setting of
* the interrupt is a pulse, so we do not need to muck
* with the ENBUSFREE logic. This also ensures that if
* the bus has moved on to another connection, busfree
* protection is still in force.
* the interrupt is a pulse, so in a perfect world, we
* would not need to muck with the ENBUSFREE logic. This
* would ensure that if the bus moves on to another
* connection, busfree protection is still in force. If
* BUSFREEREV is broken, however, we must manually clear
* the ENBUSFREE if the busfree occurred during a non-pack
* connection so that we don't get false positives during
* future, packetized, connections.
*/
ahd_outb(ahd, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
ahd_outb(ahd, CLRSINT1, CLRBUSFREE);
if (packetized == 0
&& (ahd->bugs & AHD_BUSFREEREV_BUG) != 0)
ahd_outb(ahd, SIMODE1,
ahd_inb(ahd, SIMODE1) & ~ENBUSFREE);
if (clear_fifo)
ahd_clear_fifo(ahd, mode);
ahd_clear_msg_state(ahd);
ahd_clear_intstat(ahd);
ahd_outb(ahd, CLRINT, CLRSCSIINT);
if (restart) {
ahd_restart(ahd);
} else {
@ -1066,12 +1075,13 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
static void
ahd_handle_transmission_error(struct ahd_softc *ahd)
{
u_int lqistat1;
u_int lqistat2;
u_int msg_out;
u_int curphase;
u_int lastphase;
u_int perrdiag;
u_int lqistat1;
u_int lqistat2;
u_int msg_out;
u_int curphase;
u_int lastphase;
u_int perrdiag;
u_int cur_col;
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ);
@ -1098,9 +1108,12 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
msg_out = MSG_INITIATOR_DET_ERR;
ahd_outb(ahd, CLRSINT1, CLRSCSIPERR);
printf("%s: Transmission error detected\n", ahd_name(ahd));
printf("%s: lqistat1 == 0x%x, LASTPHASE == 0x0%x, "
"curphase = 0x%x, perrdiag == 0x%x\n",
ahd_name(ahd), lqistat1, lastphase, curphase, perrdiag);
cur_col = 0;
ahd_lqistat1_print(lqistat1, &cur_col, 50);
ahd_lastphase_print(lastphase, &cur_col, 50);
ahd_scsisigi_print(curphase, &cur_col, 50);
ahd_perrdiag_print(perrdiag, &cur_col, 50);
printf("\n");
ahd_dump_card_state(ahd);
if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) {
printf("%s: Gross protocol error during incoming "
@ -1261,7 +1274,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
/*
* Packetized unexpected or expected busfree.
* Entered in MODE_SCSI.
* Entered in mode based on busfreetime.
*/
static int
ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
@ -1274,6 +1287,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
if ((lqostat1 & LQOBUSFREE) != 0) {
struct scb *scb;
u_int scbid;
u_int saved_scbptr;
u_int waiting_h;
u_int waiting_t;
u_int next;
@ -1282,8 +1296,23 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
printf("%s: Warning, BUSFREE time is 0x%x. "
"Expected BUSFREE_LQO.\n",
ahd_name(ahd), busfreetime);
scbid = ahd_get_scbptr(ahd);
/*
* The LQO manager detected an unexpected busfree
* either:
*
* 1) During an outgoing LQ.
* 2) After an outgoing LQ but before the first
* REQ of the command packet.
* 3) During an outgoing command packet.
*
* In all cases, CURRSCB is pointing to the
* SCB that encountered the failure. Clean
* up the queue, clear SELDO and LQOBUSFREE,
* and allow the sequencer to restart the select
* out at its lesure.
*/
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
scbid = ahd_inw(ahd, CURRSCB);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL)
panic("SCB not valid during LQOBUSFREE");
@ -1302,27 +1331,17 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
* Clear the status.
*/
ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE);
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
ahd_outb(ahd, CLRLQOINT1, 0);
}
/*
* The LQO manager detected an unexpected busfree
* either:
*
* 1) During an outgoing LQ.
* 2) After an outgoing LQ but before the first
* REQ of the command packet.
* 3) During an outgoing command packet.
*
* In all cases, CURRSCB is pointing to the
* SCB that encountered the failure. Clean
* up the queue, clear SELDO and LQOBUSFREE,
* and allow the sequencer to restart the select
* out at its lesure.
*/
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
ahd_outb(ahd, CLRSINT0, CLRSELDO);
/*
* Update the waiting for selection queue so
* we restart on the correct SCB.
*/
waiting_h = ahd_inw(ahd, WAITING_TID_HEAD);
saved_scbptr = ahd_get_scbptr(ahd);
if (waiting_h != scbid) {
ahd_outw(ahd, WAITING_TID_HEAD, scbid);
@ -1337,7 +1356,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
ahd_set_scbptr(ahd, scbid);
ahd_outw(ahd, SCB_NEXT2, next);
}
ahd_set_scbptr(ahd, saved_scbptr);
/* Return unpausing the sequencer. */
return (0);
}
@ -1769,6 +1788,10 @@ ahd_clear_intstat(struct ahd_softc *ahd)
|CLRLQOATNPKT|CLRLQOTCRC);
ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS
|CLRLQOBUSFREE|CLRLQOPHACHGINPKT);
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
ahd_outb(ahd, CLRLQOINT0, 0);
ahd_outb(ahd, CLRLQOINT1, 0);
}
ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR);
ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
|CLRBUSFREE|CLRSCSIPERR|CLRREQINIT);
@ -1817,26 +1840,32 @@ ahd_dump_sglist(struct scb *scb)
sg_list = (struct ahd_dma64_seg*)scb->sg_list;
for (i = 0; i < scb->sg_count; i++) {
uint64_t addr;
uint32_t len;
addr = ahd_le64toh(sg_list[i].addr);
printf("sg[%d] - Addr 0x%x%x : Length %d\n",
len = ahd_le32toh(sg_list[i].len);
printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
i,
(uint32_t)((addr >> 32) & 0xFFFFFFFF),
(uint32_t)(addr & 0xFFFFFFFF),
ahd_le32toh(sg_list[i].len));
sg_list[i].len & AHD_SG_LEN_MASK,
(sg_list[i].len & AHD_DMA_LAST_SEG)
? " Last" : "");
}
} else {
struct ahd_dma_seg *sg_list;
sg_list = (struct ahd_dma_seg*)scb->sg_list;
for (i = 0; i < scb->sg_count; i++) {
printf("sg[%d] - Addr 0x%x%x : Length %d\n",
uint32_t len;
len = ahd_le32toh(sg_list[i].len);
printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
i,
(ahd_le32toh(sg_list[i].len) >> 24
& SG_HIGH_ADDR_BITS),
(len >> 24) & SG_HIGH_ADDR_BITS,
ahd_le32toh(sg_list[i].addr),
ahd_le32toh(sg_list[i].len)
& AHD_SG_LEN_MASK);
len & AHD_SG_LEN_MASK,
len & AHD_DMA_LAST_SEG ? " Last" : "");
}
}
}
@ -2396,9 +2425,9 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
* has already been setup. The negotiation changes may
* effect whether we select-out with ATN.
*/
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
saved_scbptr = ahd_get_scbptr(ahd);
/* Ensure that the hscbs down on the card match the new information */
for (i = 0; i < ahd->scb_data.maxhscbs; i++) {
@ -2418,7 +2447,7 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
control |= pending_hscb->control & MK_MESSAGE;
ahd_outb(ahd, SCB_CONTROL, control);
}
ahd_set_scbptr(ahd,saved_scbptr);
ahd_set_scbptr(ahd, saved_scbptr);
ahd_restore_modes(ahd, saved_modes);
if (paused == 0)
@ -4725,6 +4754,10 @@ ahd_setup_iocell_workaround(struct ahd_softc *ahd)
ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL)
| BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS);
ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI));
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
printf("%s: Setting up iocell workaround\n", ahd_name(ahd));
#endif
ahd_restore_modes(ahd, saved_modes);
}
@ -4738,9 +4771,17 @@ ahd_iocell_first_selection(struct ahd_softc *ahd)
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
sblkctl = ahd_inb(ahd, SBLKCTL);
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
printf("%s: iocell first selection\n", ahd_name(ahd));
#endif
if ((sblkctl & ENAB40) != 0) {
ahd_outb(ahd, DSPDATACTL,
ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
printf("%s: BYPASS now disabled\n", ahd_name(ahd));
#endif
}
ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI));
ahd_outb(ahd, CLRINT, CLRSCSIINT);
@ -5409,7 +5450,11 @@ ahd_chip_init(struct ahd_softc *ahd)
ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75);
ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN);
ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR);
ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE);
} else {
ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
}
if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX)
/*
* Do not issue a target abort when a split completion
@ -5426,6 +5471,11 @@ ahd_chip_init(struct ahd_softc *ahd)
ahd_outb(ahd, DSPSELECT, i);
ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_CPQ_DEFAULT);
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
WRTBIASCTL_CPQ_DEFAULT);
#endif
}
ahd_setup_iocell_workaround(ahd);
@ -5460,8 +5510,7 @@ ahd_chip_init(struct ahd_softc *ahd)
ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun));
}
ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len));
ahd_outb(ahd, ATTRPTR,
offsetof(struct hardware_scb, task_attribute_nonpkt_tag));
ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute));
ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management));
ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb,
shared_data.idata.cdb));
@ -5678,6 +5727,7 @@ ahd_default_config(struct ahd_softc *ahd)
tinfo->user.offset= ~0;
tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM
| MSG_EXT_PPR_WR_FLOW
| MSG_EXT_PPR_HOLD_MCS
| MSG_EXT_PPR_IU_REQ
| MSG_EXT_PPR_QAS_REQ
| MSG_EXT_PPR_DT_REQ;
@ -5785,6 +5835,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
if ((sc->device_flags[targ] & CFPACKETIZED) != 0)
user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM
| MSG_EXT_PPR_WR_FLOW
| MSG_EXT_PPR_HOLD_MCS
| MSG_EXT_PPR_IU_REQ;
if ((sc->device_flags[targ] & CFQAS) != 0)
@ -6051,12 +6102,11 @@ ahd_resume(struct ahd_softc *ahd)
static __inline u_int
ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
{
*saved_scbid = ahd_get_scbptr(ahd);
/*
* Index to the SCB that contains the busy entry.
*/
AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
*saved_scbid = ahd_get_scbptr(ahd);
ahd_set_scbptr(ahd, TCL_LUN(tcl)
| ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4));
@ -6547,19 +6597,21 @@ int
ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status)
{
struct scb *scbp;
struct scb *scbp_next;
u_int active_scb;
u_int i, j;
u_int maxtarget;
u_int minlun;
u_int maxlun;
struct scb *scbp;
struct scb *scbp_next;
u_int active_scb;
u_int i, j;
u_int maxtarget;
u_int minlun;
u_int maxlun;
int found;
ahd_mode_state saved_modes;
int found;
/* restore this when we're done */
/* restore these when we're done */
active_scb = ahd_get_scbptr(ahd);
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL,
role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
@ -6628,6 +6680,7 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
}
}
ahd_set_scbptr(ahd, active_scb);
ahd_restore_modes(ahd, saved_modes);
ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status);
return found;
}
@ -6712,10 +6765,8 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
do {
next_fifo = next_fifo ^ CURRFIFO;
ahd_set_modes(ahd, next_fifo, next_fifo);
ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~SCSIEN);
while ((ahd_inb(ahd, DFCNTRL) & SCSIENACK) != 0)
ahd_delay(10);
ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~HDMAEN);
ahd_outb(ahd, DFCNTRL,
ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN));
while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0)
ahd_delay(10);
/*
@ -6729,7 +6780,8 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
* Reset the bus if we are initiating this reset
*/
ahd_clear_msg_state(ahd);
ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
ahd_outb(ahd, SIMODE1,
ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
if (initiate_reset)
ahd_reset_current_bus(ahd);
ahd_clear_intstat(ahd);
@ -6800,7 +6852,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
/* Notify the XPT that a bus reset occurred */
ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
ahd_restart(ahd);
/*
* Freeze the SIMQ until our poller can determine that
* the bus reset has really gone away. We set the initial
@ -6812,7 +6864,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
ahd_freeze_simq(ahd);
ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd);
}
ahd_restart(ahd);
return (found);
}
@ -6835,6 +6886,8 @@ ahd_reset_poll(void *arg)
}
ahd_lock(ahd, &s);
ahd_pause(ahd);
ahd_update_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) {
ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US,
@ -7655,6 +7708,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
u_int dffstat;
int paused;
u_int scb_index;
u_int saved_scb_index;
u_int i;
u_int cur_col;
@ -7683,6 +7737,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50);
ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50);
ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50);
ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50);
ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50);
ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50);
ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50);
@ -7691,6 +7746,14 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50);
ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50);
ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50);
ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50);
ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50);
ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50);
ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50);
ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50);
ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50);
ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50);
printf("\n");
printf("\nSCB Count = %d LASTSCB 0x%x CURRSCB 0x%x NEXTSCB 0x%x\n",
ahd->scb_data.numscbs, ahd_inw(ahd, LASTSCB),
ahd_inw(ahd, CURRSCB), ahd_inw(ahd, NEXTSCB));
@ -7699,17 +7762,17 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
CAM_LUN_WILDCARD, SCB_LIST_NULL,
ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT);
saved_scb_index = ahd_get_scbptr(ahd);
printf("Pending list:");
i = 0;
LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
if (i++ > AHD_SCB_MAX)
break;
if (scb != LIST_FIRST(&ahd->pending_scbs))
printf(", ");
cur_col = printf("\n%3d", SCB_GET_TAG(scb));
cur_col = printf("\n%3d ", SCB_GET_TAG(scb));
ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 50);
ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 50);
ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 60);
ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 60);
ahd_scb_tag_print(ahd_inb(ahd, SCB_TAG), &cur_col, 60);
}
printf("\n");
@ -7762,11 +7825,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
scb_index = ahd_inw(ahd, SCB_NEXT_COMPLETE);
}
printf("\n");
cur_col = 0;
ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50);
ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50);
ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50);
ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50);
ahd_set_scbptr(ahd, saved_scb_index);
dffstat = ahd_inb(ahd, DFFSTAT);
for (i = 0; i < 2; i++) {
#ifdef AHD_DEBUG
@ -7775,7 +7834,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
u_int fifo_scbptr;
ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
fifo_scbptr = ahd_inb(ahd, SCBPTR);
fifo_scbptr = ahd_get_scbptr(ahd);
printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, "
"SCB 0x%x, LJSCB 0x%x\n",
ahd_name(ahd), i,
@ -7822,7 +7881,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
}
#endif
}
printf("LQIN: ");
printf("\nLQIN: ");
for (i = 0; i < 20; i++)
printf("0x%x ", ahd_inb(ahd, LQIN + i));
printf("\n");
@ -7861,10 +7920,12 @@ void
ahd_dump_scbs(struct ahd_softc *ahd)
{
ahd_mode_state saved_modes;
u_int saved_scb_index;
int i;
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
saved_scb_index = ahd_get_scbptr(ahd);
for (i = 0; i < AHD_SCB_MAX; i++) {
ahd_set_scbptr(ahd, i);
printf("%3d", i);
@ -7875,6 +7936,7 @@ ahd_dump_scbs(struct ahd_softc *ahd)
ahd_inl(ahd, SCB_RESIDUAL_SGPTR));
}
printf("\n");
ahd_set_scbptr(ahd, saved_scb_index);
ahd_restore_modes(ahd, saved_modes);
}

View File

@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#56 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#61 $
*
* $FreeBSD$
*/
@ -243,7 +243,11 @@ typedef enum {
AHD_AUTOFLUSH_BUG = 0x0200,
AHD_CLRLQO_AUTOCLR_BUG = 0x0400,
AHD_PKTIZED_STATUS_BUG = 0x0800,
AHD_PKT_LUN_BUG = 0x1000
AHD_PKT_LUN_BUG = 0x1000,
AHD_MDFF_WSCBPTR_BUG = 0x2000,
AHD_REG_SLOW_SETTLE_BUG = 0x4000,
AHD_SET_MODE_BUG = 0x8000,
AHD_BUSFREEREV_BUG = 0x10000
} ahd_bug;
/*
@ -409,9 +413,9 @@ struct hardware_scb {
* transfer.
*/
#define SG_PTR_MASK 0xFFFFFFF8
/*16*/ uint8_t cdb_len;
/*17*/ uint8_t task_management;
/*18*/ uint16_t tag;
/*16*/ uint16_t tag;
/*18*/ uint8_t cdb_len;
/*19*/ uint8_t task_management;
/*20*/ uint32_t next_hscb_busaddr;
/*24*/ uint64_t dataptr;
/*32*/ uint32_t datacnt; /* Byte 3 is spare. */
@ -422,7 +426,7 @@ struct hardware_scb {
* Our Id (bits 0-3) Their ID (bits 4-7)
*/
/*42*/ uint8_t lun;
/*43*/ uint8_t task_attribute_nonpkt_tag;
/*43*/ uint8_t task_attribute;
/*44*/ uint32_t hscb_busaddr;
/******* Long lun field only downloaded for full 8 byte lun support *******/
/*48*/ uint8_t pkt_long_lun[8];

View File

@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#39 $"
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#45 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@ -56,10 +56,22 @@ VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#39 $"
#define M_DST_SHIFT 4
#define MK_MODE(src, dst) ((src) | ((dst) << M_DST_SHIFT))
#define SET_MODE(src, dst) \
SET_SRC_MODE src; \
SET_DST_MODE dst; \
mvi MK_MODE(src, dst) call set_mode_work_around
#define SET_MODE(src, dst) \
SET_SRC_MODE src; \
SET_DST_MODE dst; \
if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \
mvi MK_MODE(src, dst) call set_mode_work_around; \
} else { \
mvi MODE_PTR, MK_MODE(src, dst); \
}
#define TOGGLE_DFF_MODE \
if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \
call toggle_dff_mode_work_around; \
} else { \
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); \
}
/*
* Mode Pointer
@ -1807,7 +1819,7 @@ register SSTAT1 {
* Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
*/
register CLRSINT1 {
address 0x04c
address 0x04C
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
field CLRSELTIMEO 0x80
@ -3347,7 +3359,7 @@ scratch_ram {
REG1 {
size 2
}
REG2 {
REG_ISR {
size 2
}
SG_STATE {
@ -3464,8 +3476,8 @@ scratch_ram {
SEQ_FLAGS {
size 1
field NOT_IDENTIFIED 0x80
field TARGET_CMD_IS_TAGGED 0x40
field NO_CDB_SENT 0x40
field TARGET_CMD_IS_TAGGED 0x40
field DPHASE 0x20
/* Target flags */
field TARG_CMD_PENDING 0x10
@ -3493,6 +3505,7 @@ scratch_ram {
field CDI 0x80
field IOI 0x40
field MSGI 0x20
field P_BUSFREE 0x01
enum PHASE_MASK CDO|IOO|MSGO {
P_DATAOUT 0x0,
P_DATAIN IOO,
@ -3501,8 +3514,7 @@ scratch_ram {
P_COMMAND CDO,
P_MESGOUT CDO|MSGO,
P_STATUS CDO|IOO,
P_MESGIN CDO|IOO|MSGO,
P_BUSFREE 0x01
P_MESGIN CDO|IOO|MSGO
}
}
/*
@ -3586,10 +3598,14 @@ scratch_ram {
SEQ_FLAGS2 {
size 1
field SCB_DMA 0x01
field TARGET_MSG_PENDING 0x02
field SELECTOUT_QFROZEN 0x04
}
ALLOCFIFO_SCBPTR {
size 2
}
/*
* Target-mode CDB type to CDB length table used
* in non-packetized operation.
@ -3636,6 +3652,9 @@ scb {
size 4
alias SCB_NEXT_COMPLETE
}
SCB_TAG {
size 2
}
SCB_CDB_LEN {
size 1
field SCB_CDB_LEN_PTR 0x80 /* CDB in host memory */
@ -3643,9 +3662,6 @@ scb {
SCB_TASK_MANAGEMENT {
size 1
}
SCB_TAG {
size 2
}
SCB_NEXT {
alias SCB_NEXT_SCB_BUSADDR
size 2

View File

@ -40,7 +40,7 @@
* $FreeBSD$
*/
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#51 $"
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#60 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_"
@ -48,7 +48,7 @@ PREFIX = "ahd_"
#include "scsi_message.h"
idle_loop:
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus;
test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus;
cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus;
@ -94,14 +94,9 @@ good_status_IU_done:
* 2) Configured and draining to the host, no pending CLRCHN.
* 3) Pending cfg4data, fifo not empty.
*
* For case 1, we assume that our DMA post of the completed command
* will occur after the FIFO finishes draining due to the higher
* priority of data FIFO transfers relative to command channel
* transfers.
*
* Case 2 can be detected by noticing that a longjmp is active for the
* FIFO and LONGJMP_SCB matches our SCB. In this case, we allow
* the routine servicing the FIFO to complete the SCB.
* Cases 1 and 2 can be detected by noticing that a longjmp is
* active for the FIFO and LONGJMP_SCB matches our SCB. In this
* case, we allow the routine servicing the FIFO to complete the SCB.
*
* Case 3 implies either a pending or yet to occur save data
* pointers for this same context in the other FIFO. So, if
@ -123,21 +118,21 @@ BEGIN_CRITICAL;
good_status_check_fifos:
clc;
bmov ARG_1, SCBPTR, 2;
SET_MODE(M_DFF0, M_DFF0);
SET_MODE(M_DFF0, M_DFF0)
call check_fifo;
jc idle_loop_service_fifos;
SET_MODE(M_DFF1, M_DFF1);
SET_MODE(M_DFF1, M_DFF1)
call check_fifo;
jc idle_loop_service_fifos;
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
call queue_scb_completion;
END_CRITICAL;
idle_loop_service_fifos:
SET_MODE(M_DFF0, M_DFF0);
SET_MODE(M_DFF0, M_DFF0)
test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo;
call longjmp;
idle_loop_next_fifo:
SET_MODE(M_DFF1, M_DFF1);
SET_MODE(M_DFF1, M_DFF1)
test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_last_fifo_done;
call longjmp;
idle_loop_last_fifo_done:
@ -145,10 +140,12 @@ idle_loop_last_fifo_done:
jmp idle_loop;
idle_loop_cchan:
SET_MODE(M_CCHAN, M_CCHAN);
SET_MODE(M_CCHAN, M_CCHAN)
BEGIN_CRITICAL;
test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle;
test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog;
test CCSCBCTL, CCSCBDONE jz return;
END_CRITICAL;
/* FALLTHROUGH */
scbdma_tohost_done:
test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
@ -168,6 +165,7 @@ fill_qoutfifo_dmadone:
bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4;
xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret;
BEGIN_CRITICAL;
fetch_new_scb_inprog:
test CCSCBCTL, ARRDONE jz return;
fetch_new_scb_done:
@ -207,6 +205,7 @@ first_new_scb:
bmov WAITING_TID_TAIL, REG0, 2;
/* Increment our position in the QINFIFO. */
mov NONE, SNSCB_QOFF ret;
END_CRITICAL;
scbdma_idle:
/*
@ -278,8 +277,7 @@ SET_SRC_MODE M_CCHAN;
SET_DST_MODE M_CCHAN;
dma_scb:
mvi SCBHCNT, SCB_TRANSFER_SIZE;
mov CCSCBCTL, SINDEX;
or SEQ_FLAGS2, SCB_DMA ret;
mov CCSCBCTL, SINDEX ret;
BEGIN_CRITICAL;
setjmp_setscb:
@ -299,11 +297,18 @@ END_CRITICAL;
* fail to store the new mode value for restoration on
* an iret.
*/
if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {
set_mode_work_around:
mvi SEQINTCTL, INTVEC1DSL;
mov MODE_PTR, SINDEX;
clr SEQINTCTL ret;
toggle_dff_mode_work_around:
mvi SEQINTCTL, INTVEC1DSL;
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
clr SEQINTCTL ret;
}
SET_SRC_MODE M_SCSI;
SET_DST_MODE M_SCSI;
start_selection:
@ -361,21 +366,20 @@ allocate_fifo_loop:
/*
* Do whatever work is required to free a FIFO.
*/
SET_MODE(M_DFF0, M_DFF0);
SET_MODE(M_DFF0, M_DFF0)
test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2;
call longjmp;
SET_MODE(M_DFF1, M_DFF1);
SET_MODE(M_DFF1, M_DFF1)
test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2;
call longjmp;
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
allocate_fifo:
and A, FIFO0FREE|FIFO1FREE, DFFSTAT;
cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop;
take_fifo:
bmov ARG_1, SCBPTR, 2;
or DFFSTAT, CURRFIFO;
SET_MODE(M_DFF1, M_DFF1);
bmov SCBPTR, ARG_1, 2 ret;
SET_MODE(M_DFF1, M_DFF1)
bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;
/*
* We have been reselected as an initiator
@ -384,6 +388,17 @@ take_fifo:
SET_SRC_MODE M_SCSI;
SET_DST_MODE M_SCSI;
select_in:
if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
/*
* This exposes a window whereby a
* busfree just after a selection will
* be missed, but there is not other safe
* way to enable busfree detection if
* the busfreerev function is broken.
*/
mvi CLRSINT1,CLRBUSFREE;
or SIMODE1, ENBUSFREE;
}
or SXFRCTL0, SPIOEN;
and SAVED_SCSIID, SELID_MASK, SELID;
and A, OID, IOWNID;
@ -493,7 +508,6 @@ select_out_list_done:
*/
test SCB_CONTROL, MK_MESSAGE jnz select_out_inc_tid_q;
shr DINDEX, 3, SCB_SCSIID;
/* XXX When we switch to SCB_SELOID, put +1 in addition below. */
or DINDEX, 1; /* Want only the second byte */
mvi DINDEX[1], ((WAITING_SCB_TAILS) >> 8);
mvi DINDIR, SCB_LIST_NULL;
@ -529,6 +543,17 @@ select_out_no_message:
select_out_non_packetized:
/* Non packetized request. */
and SCSISEQ0, ~ENSELO;
if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
/*
* This exposes a window whereby a
* busfree just after a selection will
* be missed, but there is not other safe
* way to enable busfree detection if
* the busfreerev function is broken.
*/
mvi CLRSINT1,CLRBUSFREE;
or SIMODE1, ENBUSFREE;
}
mov SAVED_SCSIID, SCB_SCSIID;
mov SAVED_LUN, SCB_LUN;
or SXFRCTL0, SPIOEN;
@ -576,6 +601,7 @@ SET_DST_MODE M_DFF1;
*/
mvi DFFSXFRCTL, RSTCHN|CLRSHCNT;
p_command_allocate_fifo:
bmov ALLOCFIFO_SCBPTR, SCBPTR, 2;
call allocate_fifo;
add NONE, -17, SCB_CDB_LEN;
jnc p_command_embedded;
@ -744,13 +770,10 @@ mesgin_done:
mov NONE,SCSIDAT; /*dummy read from latch to ACK*/
jmp ITloop;
#define INDEX_DISC_LIST_SCB(scsiid, lun) \
#define INDEX_DISC_LIST(scsiid, lun) \
and A, 0xC0, scsiid; \
or SCBPTR, A, lun; \
clr SCBPTR[1]
#define INDEX_DISC_LIST(scsiid, lun) \
INDEX_DISC_LIST_SCB(scsiid, lun); \
clr SCBPTR[1]; \
and SINDEX, 0x30, scsiid; \
shr SINDEX, 3; /* Multiply by 2 */ \
add SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF); \
@ -819,7 +842,8 @@ setup_SCB:
setup_SCB_disconnected:
and SCB_CONTROL,~DISCONNECTED;
clr SEQ_FLAGS; /* make note of IDENTIFY */
test SCB_SGPTR, SG_LIST_NULL jnz . + 2;
test SCB_SGPTR, SG_LIST_NULL jnz . + 3;
bmov ALLOCFIFO_SCBPTR, SCBPTR, 2;
call allocate_fifo;
/* See if the host wants to send a message upon reconnection */
test SCB_CONTROL, MK_MESSAGE jz mesgin_done;
@ -910,7 +934,7 @@ freeze_queue:
mov A, ACCUM_SAVE ret;
queue_arg1_scb_completion:
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
bmov SCBPTR, ARG_1, 2;
queue_scb_completion:
test SCB_SCSI_STATUS,0xff jnz bad_status;
@ -962,8 +986,15 @@ queue_disc_scb:
/* FALLTHROUGH */
await_busfree:
and SIMODE1, ~ENBUSFREE;
if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) {
/*
* In the BUSFREEREV_BUG case, the
* busfree status was cleared at the
* beginning of the connection.
*/
mvi CLRSINT1,CLRBUSFREE;
}
mov NONE, SCSIDAT; /* Ack the last byte */
call clear_target_state;
test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
jnz await_busfree_not_m_dff;
SET_SRC_MODE M_DFF1;
@ -971,6 +1002,7 @@ SET_DST_MODE M_DFF1;
await_busfree_clrchn:
mvi DFFSXFRCTL, CLRCHN;
await_busfree_not_m_dff:
call clear_target_state;
test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz idle_loop;
mvi SEQINTCODE, MISSED_BUSFREE;
@ -1080,20 +1112,19 @@ disable_ccsgen:
disable_ccsgen_fetch_done:
clr SG_STATE ret;
toggle_dff_mode:
mvi SEQINTCTL, INTVEC1DSL;
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
clr SEQINTCTL ret;
data_group_idle_loop:
mov SAVED_MODE, MODE_PTR;
test SG_STATE, LOADING_NEEDED jz . + 2;
call service_fifo;
call toggle_dff_mode;
TOGGLE_DFF_MODE
test SG_STATE, LOADING_NEEDED jz . + 2;
call service_fifo;
call idle_loop_cchan;
mov SAVED_MODE jmp set_mode_work_around;
if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {
mov SAVED_MODE jmp set_mode_work_around;
} else {
mov MODE_PTR, SAVED_MODE ret;
}
service_fifo:
/*
@ -1120,8 +1151,16 @@ service_fifo:
* set the prefetch amount to a reasonable level if the
* cacheline size is unknown.
*/
mvi SGHCNT, SG_PREFETCH_CNT;
and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
mvi SGHCNT, SG_PREFETCH_CNT;
if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {
/*
* Need two instruction between "touches" of SGHADDR.
* Note the setting of SGHCNT counts as one of
* these two instructions.
*/
nop;
}
bmov SGHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET;
or SG_STATE, FETCH_INPROG ret;
@ -1190,12 +1229,12 @@ sg_advance:
load_first_seg:
bmov HADDR, SCB_DATAPTR, 11;
and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
and REG0, ~SG_FULL_RESID, SCB_SGPTR[0];
and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0];
test SCB_DATACNT[3], SG_LAST_SEG jz . + 2;
or REG0, LAST_SEG;
or REG_ISR, LAST_SEG;
test DATA_COUNT_ODD, 0x1 jz . + 2;
or REG0, ODD_SEG;
mov SG_CACHE_PRE, REG0;
or REG_ISR, ODD_SEG;
mov SG_CACHE_PRE, REG_ISR;
mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
/*
* Since we've are entering a data phase, we will
@ -1225,6 +1264,7 @@ p_data_allowed:
*/
test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;
mvi SEQINTCODE, PDATA_REINIT;
jmp data_group_dma_loop;
p_data_bitbucket:
/*
@ -1239,12 +1279,13 @@ p_data_bitbucket:
* doesn't discard data already in the FIFO.
*/
mvi DFFSXFRCTL, RSTCHN|CLRSHCNT;
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
bitbucket_not_m_dff:
or SXFRCTL1,BITBUCKET;
test SCSIPHASE, DATA_PHASE_MASK jnz .;
/* Wait for non-data phase. */
test SCSIPHASE, ~DATA_PHASE_MASK jz .;
and SXFRCTL1, ~BITBUCKET;
SET_MODE(M_DFF1, M_DFF1);
SET_MODE(M_DFF1, M_DFF1)
mvi SEQINTCODE, DATA_OVERRUN;
jmp ITloop;
@ -1327,7 +1368,7 @@ data_phase_done:
test DFCNTRL, DIRECTION jz target_ITloop;
test SSTAT1, REQINIT jnz .;
test DATA_COUNT_ODD, 0x1 jz target_ITloop;
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
test NEGCONOPTS, WIDEXFER jz target_ITloop;
*/
/*
@ -1463,7 +1504,7 @@ cfg4istat_setup_handler:
/*
* See if the target has gone on in this context creating an
* overrun condition. For the write case, the hardware cannot
* ack bytes until data is provided. So, if the target begins
* ack bytes until data are provided. So, if the target begins
* another packet without changing contexts, implying we are
* not sitting on a packet boundary, we are in an overrun
* situation. For the read case, the hardware will continue to
@ -1503,8 +1544,46 @@ pkt_last_seg:
test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
test SCSISIGO, ATNO jnz . + 2;
test SSTAT2, NONPACKREQ jz return;
test MDFFSTAT, SHVALID jnz pkt_saveptrs;
jmp return;
test MDFFSTAT, SHVALID jz return;
/* FALLTHROUGH */
/*
* Either a SAVEPTRS interrupt condition is pending for this FIFO
* or we have a pending nonpackreq for this FIFO. We differentiate
* between the two by capturing the state of the SAVEPTRS interrupt
* prior to clearing this status and executing the common code for
* these two cases.
*/
pkt_saveptrs:
BEGIN_CRITICAL;
if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
or DFCNTRL, FIFOFLUSH;
}
mov REG0, SEQINTSRC;
call calc_residual;
call save_pointers;
mvi CLRSEQINTSRC, CLRSAVEPTRS;
call disable_ccsgen;
or SEQIMODE, ENSAVEPTRS;
test DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status;
test DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status;
/*
* Keep a handler around for this FIFO until it drains
* to the host to guarantee that we don't complete the
* command to the host before the data arrives.
*/
pkt_saveptrs_wait_fifoemp:
call setjmp;
test DFSTATUS, FIFOEMP jz return;
pkt_saveptrs_check_status:
or LONGJMP_ADDR[1], INVALID_ADDR;
test REG0, SAVEPTRS jz unexpected_nonpkt_phase;
test SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn;
jmp last_pkt_complete;
pkt_saveptrs_clrchn:
mvi DFFSXFRCTL, CLRCHN ret;
END_CRITICAL;
last_pkt_done:
BEGIN_CRITICAL;
if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
@ -1514,10 +1593,11 @@ BEGIN_CRITICAL;
check_overrun;
or SCB_SGPTR, SG_LIST_NULL;
/*
* I think it is safe to skip the FIFO check.
* in this case as LAST_SEG_DONE implies
* the other FIFO, if ever active for this transfer,
* has completed.
* It is safe to skip the other FIFO check since
* we defer CLRCHN on SAVEPTRS until all data in
* the FIFO are seen by the host and a CFG4DATA
* in this FIFO for the same context is held off
* by hardware.
*/
last_pkt_queue_scb:
or LONGJMP_ADDR[1], INVALID_ADDR;
@ -1530,7 +1610,7 @@ last_pkt_complete:
mvi DFFSXFRCTL, CLRCHN;
check_other_fifo:
clc;
call toggle_dff_mode;
TOGGLE_DFF_MODE
call check_fifo;
jnc queue_arg1_scb_completion;
return:
@ -1553,32 +1633,6 @@ BEGIN_CRITICAL;
mvi DFFSXFRCTL, CLRCHN ret;
END_CRITICAL;
/*
* Either a SAVEPTRS interrupt condition is pending for this FIFO
* or we have a pending nonpackreq for this FIFO. We differentiate
* between the two by capturing the state of the SAVEPTRS interrupt
* prior to clearing and handling the common code of these two cases.
*/
pkt_saveptrs:
BEGIN_CRITICAL;
if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
or DFCNTRL, FIFOFLUSH;
}
mov REG0, SEQINTSRC;
mvi CLRSEQINTSRC, CLRSAVEPTRS;
call calc_residual;
call save_pointers;
call disable_ccsgen;
or SEQIMODE, ENSAVEPTRS;
or LONGJMP_ADDR[1], INVALID_ADDR;
pkt_saveptrs_check_status:
test REG0, SAVEPTRS jz unexpected_nonpkt_phase;
test SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn;
jmp last_pkt_complete;
pkt_saveptrs_clrchn:
mvi DFFSXFRCTL, CLRCHN ret;
END_CRITICAL;
check_status_overrun:
test SHCNT[2], 0xFF jz status_IU_done;
mvi SEQINTCODE, STATUS_OVERRUN;
@ -1657,7 +1711,7 @@ pkt_handle_overrun:
mvi SEQINTCODE, CFG4OVERRUN;
call freeze_queue;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) {
SET_MODE(M_SCSI, M_SCSI);
SET_MODE(M_SCSI, M_SCSI)
or SXFRCTL1,BITBUCKET;
SET_SRC_MODE M_DFF1;
SET_DST_MODE M_DFF1;

View File

@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#34 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#36 $
*
* $FreeBSD$
*/
@ -226,48 +226,6 @@ ahd_unpause(struct ahd_softc *ahd)
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
}
/*********************** Untagged Transaction Routines ************************/
static __inline void ahd_freeze_untagged_queues(struct ahd_softc *ahd);
static __inline void ahd_release_untagged_queues(struct ahd_softc *ahd);
/*
* Block our completion routine from starting the next untagged
* transaction for this target or target lun.
*/
static __inline void
ahd_freeze_untagged_queues(struct ahd_softc *ahd)
{
/*
* Assume we have enough space in the card's SCB
* to obviate the need for a per target untagged
* transaction limit.
*/
#if 0
ahd->untagged_queue_lock++;
#endif
}
/*
* Allow the next untagged transaction for this target or target lun
* to be executed. We use a counting semaphore to allow the lock
* to be acquired recursively. Once the count drops to zero, the
* transaction queues will be run.
*/
static __inline void
ahd_release_untagged_queues(struct ahd_softc *ahd)
{
/*
* Assume we have enough space in the card's SCB
* to obviate the need for a per target untagged
* transaction limit.
*/
#if 0
ahd->untagged_queue_lock--;
if (ahd->untagged_queue_lock == 0)
ahd_run_untagged_queues(ahd);
#endif
}
/*********************** Scatter Gather List Handling *************************/
static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
void *sgptr, bus_addr_t addr,
@ -296,7 +254,7 @@ ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
struct ahd_dma_seg *sg;
sg = (struct ahd_dma_seg *)sgptr;
sg->addr = ahd_htole64(addr);
sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
| (last ? AHD_DMA_LAST_SEG : 0));
return (sg + 1);
@ -309,15 +267,12 @@ ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
/* XXX Handle target mode SCBs. */
if ((scb->flags & SCB_PACKETIZED) != 0) {
/* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
scb->hscb->task_attribute_nonpkt_tag =
scb->hscb->control & SCB_TAG_TYPE;
scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE;
scb->hscb->task_management = 0;
/*
* For Rev A short lun workaround.
*/
scb->hscb->pkt_long_lun[6] = scb->hscb->lun;
} else {
scb->hscb->task_attribute_nonpkt_tag = SCB_GET_TAG(scb);
}
if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
@ -783,7 +738,6 @@ ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
scb->hscb = q_hscb;
/* Now define the mapping from tag to SCB in the scbindex */
/* XXX This should be constant now. Can we avoid the mapping? */
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
}

View File

@ -38,7 +38,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#41 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#44 $
*
* $FreeBSD$
*/
@ -791,7 +791,9 @@ ahd_aic7902_setup(struct ahd_softc *ahd)
| AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG
| AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG
| AHD_PCIX_CHIPRST_BUG|AHD_PKTIZED_STATUS_BUG
| AHD_PKT_LUN_BUG;
| AHD_PKT_LUN_BUG|AHD_MDFF_WSCBPTR_BUG
| AHD_REG_SLOW_SETTLE_BUG|AHD_SET_MODE_BUG
| AHD_BUSFREEREV_BUG;
}
ahd->channel = ahd_get_pci_function(pci) + 'A';