aic7xxx.c:

Style nits.

	Make sure that our selection hardware is disabled
	as soon as possible after detecting a busfree and
	even go so far as to disable the selection hardware
	in advance of an event that will cause a busfree
	(ABORT or BUS DEVICE RESET message).  The concern
	is that the selection hardware will select a target
	for which, after processing the bus free, there
	will be no commands pending.  The sequencer idle
	loop will re-enable the selection should it still be
	necessary.

	In ahc_handle_scsiint(), clear SSTAT0 events several
	PCI transactions (most notably reads) prior to clearing
	SCSIINT.  The newer chips seem to take a bit of time to
	see the change which can make the clearing of SCSIINT
	ineffective.

	Don't bother panicing at the end of ahc_handle_scsiint().
	Getting to the final else just means we lost the race
	with clearing SCSIINT.

	In ahc_free(), handle init-level 0.  This can happen when we
	fail the attach for RAID devices.  While I'm here, also kill
	the parent dma tag.

	In ahc_match_scb(), consider initiator ccbs to be any
	that are not from the target mode group.  This fixes
	a bug where an external target reset CCB was not getting
	cleaned up by the reset code.

	Don't bother freezing a ccb in any of our "abort" routines
	when the status is set to CAM_REQ_CMP.  This can happen
	for a target reset ccb.

aic7xxx.reg:
	Reserve space for a completion queue.  This will be used
	to enhance performance in the near future.

aic7xxx.seq:
	Remove an optimization for the 7890 autoflush bug that
	turned out to allow, in rare cases, some data to get
	lost.

	Implement a simpler, faster, fix for the PCI_2_1 retry
	bug that hangs the sequencer on an SCB dma for certain chips.

	Test against SAVED_SCSIID rather than SELID during target
	reselections.  This is how we always did it in the past,
	but the code was modified while trying to work around an
	issue with the 7895.  SAVED_SCSIID takes into account
	twin channel adapters such as the 2742T, whereas SELID
	does not have the channel bit.  This caused invalid
	selection warnings and other strangeness on these cards.

aic7xxx_pci.c
	Use the correct mask for checking the generic aic7892
	entry.
This commit is contained in:
Justin T. Gibbs 2001-02-10 18:04:27 +00:00
parent 49ed07a3c0
commit bfadd24d57
5 changed files with 175 additions and 78 deletions

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: //depot/src/aic7xxx/aic7xxx.c#26 $
* $Id: //depot/src/aic7xxx/aic7xxx.c#28 $
*
* $FreeBSD$
*/
@ -977,8 +977,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
if (scb != NULL)
ahc_print_path(ahc, scb);
else
printf("%s:%c:%d: ", ahc_name(ahc),
intr_channel,
printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
scsirate = ahc_inb(ahc, SCSIRATE);
printf("parity error detected %s. "
@ -1017,22 +1016,46 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
unpause_sequencer(ahc);
} else if ((status & BUSFREE) != 0
&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
u_int lastphase;
u_int saved_scsiid;
u_int saved_lun;
u_int target;
u_int initiator_role_id;
char channel;
int printerror;
/*
* First look at what phase we were last in.
* Clear our selection hardware as soon as possible.
* We may have an entry in the waiting Q for this target,
* that is affected by this busfree and we don't want to
* go about selecting the target while we handle the event.
*/
ahc_outb(ahc, SCSISEQ,
ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
/*
* Disable busfree interrupts and clear the busfree
* interrupt status. We do this here so that several
* bus transactions occur prior to clearing the SCSIINT
* latch. It can take a bit for the clearing to take effect.
*/
ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
/*
* Look at what phase we were last in.
* If its message out, chances are pretty good
* that the busfree was in response to one of
* our abort requests.
*/
u_int lastphase = ahc_inb(ahc, LASTPHASE);
u_int saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
u_int saved_lun = ahc_inb(ahc, SAVED_LUN);
u_int target = SCSIID_TARGET(ahc, saved_scsiid);
u_int initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
char channel = SCSIID_CHANNEL(ahc, saved_scsiid);
int printerror = 1;
lastphase = ahc_inb(ahc, LASTPHASE);
saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
saved_lun = ahc_inb(ahc, SAVED_LUN);
target = SCSIID_TARGET(ahc, saved_scsiid);
initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
channel = SCSIID_CHANNEL(ahc, saved_scsiid);
printerror = 1;
ahc_outb(ahc, SCSISEQ,
ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
if (lastphase == P_MESGOUT) {
struct ahc_devinfo devinfo;
u_int tag;
@ -1155,26 +1178,11 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
| (ahc_inb(ahc, SEQADDR1) << 8));
}
ahc_clear_msg_state(ahc);
ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
restart_sequencer(ahc);
} else if ((status & SELTO) != 0) {
u_int scbptr;
scbptr = ahc_inb(ahc, WAITING_SCBH);
ahc_outb(ahc, SCBPTR, scbptr);
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
printf("%s: ahc_intr - referenced scb not "
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
} else {
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
}
/* Stop the selection */
ahc_outb(ahc, SCSISEQ, 0);
@ -1194,11 +1202,25 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
*/
ahc_outb(ahc, CLRSINT0, CLRSELINGO);
scbptr = ahc_inb(ahc, WAITING_SCBH);
ahc_outb(ahc, SCBPTR, scbptr);
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
printf("%s: ahc_intr - referenced scb not "
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
} else {
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
}
ahc_outb(ahc, CLRINT, CLRSCSIINT);
restart_sequencer(ahc);
} else {
panic("%s: Missing case in ahc_handle_scsiint. status = %x\n",
printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
ahc_name(ahc), status);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
}
}
@ -2027,6 +2049,14 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_len++;
ahc_print_path(ahc, scb);
printf("Bus Device Reset Message Sent\n");
/*
* Clear our selection hardware in advance of
* the busfree. We may have an entry in the waiting
* Q for this target, and we don't want to go about
* selecting while we handle the busfree and blow it
* away.
*/
ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
} else if ((scb->flags & SCB_ABORT) != 0) {
if ((scb->hscb->control & TAG_ENB) != 0)
ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG;
@ -2034,7 +2064,16 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
ahc->msgout_len++;
ahc_print_path(ahc, scb);
printf("Abort Message Sent\n");
printf("Abort%s Message Sent\n",
(scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
/*
* Clear our selection hardware in advance of
* the busfree. We may have an entry in the waiting
* Q for this target, and we don't want to go about
* selecting while we handle the busfree and blow it
* away.
*/
ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
} else if ((ahc->targ_msg_req & devinfo->target_mask) != 0
|| (scb->flags & SCB_NEGOTIATE) != 0) {
ahc_build_transfer_msg(ahc, devinfo);
@ -3268,7 +3307,7 @@ ahc_alloc(void *platform_arg, char *name)
#endif
memset(ahc, 0, sizeof(*ahc));
LIST_INIT(&ahc->pending_scbs);
/* We don't know or unit number until the OSM sets it */
/* We don't know our unit number until the OSM sets it */
ahc->name = name;
for (i = 0; i < 16; i++)
TAILQ_INIT(&ahc->untagged_queues[i]);
@ -3397,8 +3436,13 @@ ahc_free(struct ahc_softc *ahc)
ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
#endif
break;
case 0:
break;
}
#ifndef __linux__
ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
#endif
ahc_platform_free(ahc);
for (i = 0; i < AHC_NUM_TARGETS; i++) {
struct tmode_tstate *tstate;
@ -4682,7 +4726,7 @@ ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code);
if (role == ROLE_INITIATOR) {
match = (group == XPT_FC_GROUP_COMMON)
match = (group != XPT_FC_GROUP_TMODE)
&& ((tag == scb->hscb->tag)
|| (tag == SCB_LIST_NULL));
} else if (role == ROLE_TARGET) {
@ -4820,11 +4864,14 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
case SEARCH_COMPLETE:
{
cam_status ostat;
cam_status cstat;
ostat = ahc_get_transaction_status(scb);
if (ostat == CAM_REQ_INPROG)
ahc_set_transaction_status(scb,
status);
cstat = ahc_get_transaction_status(scb);
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
printf("Inactive SCB in qinfifo\n");
@ -4920,11 +4967,14 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
case SEARCH_COMPLETE:
{
cam_status ostat;
cam_status cstat;
ostat = ahc_get_transaction_status(scb);
if (ostat == CAM_REQ_INPROG)
ahc_set_transaction_status(scb,
status);
cstat = ahc_get_transaction_status(scb);
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
printf("Inactive SCB in Waiting List\n");
@ -4998,11 +5048,14 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
case SEARCH_COMPLETE:
{
cam_status ostat;
cam_status cstat;
ostat = ahc_get_transaction_status(scb);
if (ostat == CAM_REQ_INPROG)
ahc_set_transaction_status(scb,
status);
cstat = ahc_get_transaction_status(scb);
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
printf("Inactive SCB in untaggedQ\n");
@ -5289,6 +5342,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
ostat = ahc_get_transaction_status(scbp);
if (ostat == CAM_REQ_INPROG)
ahc_set_transaction_status(scbp, status);
if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP)
ahc_freeze_scb(scbp);
if ((scbp->flags & SCB_ACTIVE) == 0)
printf("Inactive SCB on pending list\n");

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: //depot/src/aic7xxx/aic7xxx.h#17 $
* $Id: //depot/src/aic7xxx/aic7xxx.h#18 $
*
* $FreeBSD$
*/

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: //depot/src/aic7xxx/aic7xxx.reg#10 $
* $Id: //depot/src/aic7xxx/aic7xxx.reg#12 $
*
* $FreeBSD$
*/
@ -1352,6 +1352,14 @@ scratch_ram {
FREE_SCBH {
size 1
}
/*
* head of list of SCBs that have
* completed but have not been
* put into the qoutfifo.
*/
COMPLETE_SCBH {
size 1
}
/*
* Address of the hardware scb array in the host.
*/

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: //depot/src/aic7xxx/aic7xxx.seq#16 $
* $Id: //depot/src/aic7xxx/aic7xxx.seq#19 $
*
* $FreeBSD$
*/
@ -902,10 +902,9 @@ ultra2_dma_loop:
ultra2_dmafinish:
test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
if ((ahc->features & AHC_DT) == 0) {
and DFCNTRL, ~SCSIEN;
test DFCNTRL, SCSIEN jnz .;
if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
test DFSTATUS, FIFOEMP jnz ultra2_dmafifoempty;
}
ultra2_dmafifoflush:
if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
@ -1464,9 +1463,10 @@ mesgin_complete:
* If ATN is raised, we still want to give the target a message.
* Perhaps there was a parity error on this last message byte.
* Either way, the target should take us to message out phase
* and then attempt to complete the command again.
* XXX - Need a critical section to do this corrctly. Wait until
* we queue completions.
* and then attempt to complete the command again. We should use a
* critical section here to guard against a timeout triggering
* for this command and setting ATN while we are still processing
* the completion.
test SCSISIGI, ATNI jnz mesgin_done;
*/
@ -1609,7 +1609,7 @@ mesgin_identify:
* for this target or the transaction is for a different lun, then
* this must be an untagged transaction.
*/
shr SINDEX, 4, SELID;
shr SINDEX, 4, SAVED_SCSIID;
and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
if ((ahc->flags & AHC_SCB_BTT) != 0) {
add SINDEX, SCB_64_BTT;
@ -2035,13 +2035,13 @@ dma_scb_fromhost:
* continue the transfer. This does not
* happen for SCSI transfers as the SCSI module
* will drain the FIFO as data is made available.
* When the hang occurs, we know that at least
* 8 bytes are in the FIFO because the PCI
* When the hang occurs, we know that a multiple
* of 8 bytes are in the FIFO because the PCI
* module has an 8 byte input latch that only
* dumps to the FIFO when HCNT == 0 or the
* latch is full.
*/
mvi A, -24;
clr A;
/* Wait for some data to arrive. */
dma_scb_hang_fifo:
test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
@ -2051,34 +2051,43 @@ dma_scb_hang_wait:
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
/*
* The PCI no longer intends to perform a PCI
* transaction and HDONE has not come true.
* The PCI module no longer intends to perform
* a PCI transaction and HDONE has not come true.
* We are hung. Drain the fifo.
*/
dma_scb_hang_empty_fifo:
call dfdat_in_8;
add A, 8;
add SINDEX, A, HCNT;
/*
* The result will be <= 0 (carry set) if at
* least 8 bytes of data have been placed
* into the fifo.
* Skip lines not yet transfered into the FIFO.
*/
jc dma_scb_hang_empty_fifo;
add SINDEX, 7, HCNT;
shr SINDEX, 3;
/*
* Skip lines already copied out of the FIFO.
*/
add A, A, SINDEX;
call dma_scb_hang_dma_drain_fifo;
/*
* Set the lines transferred to all but
* those yet to reach the FIFO.
*/
not SINDEX;
add A, 5, SINDEX;
jmp dma_scb_hang_fifo;
dma_scb_hang_dma_done:
and DFCNTRL, ~HDMAEN;
test DFCNTRL, HDMAEN jnz .;
call dfdat_in_8;
add A, 8;
cmp A, 8 jne . - 2;
dma_scb_hang_dma_drain_fifo:
add SEQADDR0, A;
} else {
call dma_finish;
}
/* If we were putting the SCB, we are done */
call dfdat_in_8;
call dfdat_in_8;
call dfdat_in_8;
}
dfdat_in_8:
mov DINDIR,DFDAT;
dfdat_in_7:

View File

@ -65,6 +65,7 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull
#define ID_AIC7850 0x5078900400000000ull
#define ID_AHA_2910_15_20_30C 0x5078900478509004ull
#define ID_AIC7855 0x5578900400000000ull
@ -134,6 +135,23 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AIC7810 0x1078900400000000ull
#define ID_AIC7815 0x7815900400000000ull
#define DEVID_9005_TYPE(id) ((id) & 0xF)
#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */
#define DEVID_9005_TYPE_AAA 0x3 /* RAID Card */
#define DEVID_9005_TYPE_SISL 0x5 /* Low Cost Card */
#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */
#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
#define DEVID_9005_MAXRATE_U160 0x0
#define DEVID_9005_MAXRATE_ULTRA2 0x1
#define DEVID_9005_MAXRATE_ULTRA 0x2
#define DEVID_9005_MAXRATE_FAST 0x3
#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6)
#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8)
#define DEVID_9005_CLASS_SPI 0x0 /* Parallel SCSI */
#define SUBID_9005_TYPE(id) ((id) & 0xF)
#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */
#define SUBID_9005_TYPE_CARD 0x0 /* Standard Card */
@ -509,14 +527,14 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
ahc_aic7880_setup
},
{
ID_AIC7890 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
ID_AIC7890 & ID_9005_GENERIC_MASK,
ID_9005_GENERIC_MASK,
"Adaptec aic7890/91 Ultra2 SCSI adapter",
ahc_aic7890_setup
},
{
ID_AIC7892 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
ID_AIC7892 & ID_9005_GENERIC_MASK,
ID_9005_GENERIC_MASK,
"Adaptec aic7892 Ultra160 SCSI adapter",
ahc_aic7892_setup
},
@ -533,14 +551,14 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
ahc_aic7895_setup
},
{
ID_AIC7896 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
ID_AIC7896 & ID_9005_GENERIC_MASK,
ID_9005_GENERIC_MASK,
"Adaptec aic7896/97 Ultra2 SCSI adapter",
ahc_aic7896_setup
},
{
ID_AIC7899 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
ID_AIC7899 & ID_9005_GENERIC_MASK,
ID_9005_GENERIC_MASK,
"Adaptec aic7899 Ultra160 SCSI adapter",
ahc_aic7899_setup
},
@ -792,6 +810,7 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
printf("%s: Using left over BIOS settings\n",
ahc_name(ahc));
ahc->flags &= ~AHC_USEDEFAULTS;
ahc->flags |= AHC_BIOS_ENABLED;
} else {
/*
* Assume only one connector and always turn
@ -1227,8 +1246,15 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if (sc.adapter_control & CFRESETB)
scsi_conf |= RESET_SCSI;
if ((sc.adapter_control & CFCHNLBPRIMARY) != 0
&& (ahc->features & AHC_MULTI_FUNC) != 0)
ahc->flags |= AHC_CHANNEL_B_PRIMARY;
if (sc.bios_control & CFEXTEND)
ahc->flags |= AHC_EXTENDED_TRANS_A;
if (sc.bios_control & CFBIOSEN)
ahc->flags |= AHC_BIOS_ENABLED;
if (ahc->features & AHC_ULTRA
&& (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
/* Should we enable Ultra mode? */