ahc_eisa.c:
ahc_pci.c: Prepare for making ahc a module by adding module dependency and version info. aic7770.c: Remove linux header ifdefs. The headers are handled differently in Linux where local includes (those using "'s instead of <>'s) are allowed. Don't map our interrupt until after we are fully setup to handle interrupts. Our interrupt line may be shared so an interrupt could occur at any time. aic7xxx.c: Remove linux header ifdefs. current->curr to avoid Linux's use of current as a #define for the current task on some architectures. Add a helper function, ahc_assert_atn(), for use in message phases we handle manually. This hides the fact that U160 chips with the expected phase matching disabled need to have SCSISIGO updated differently. if (ahc_check_residual(scb) != 0) ahc_calc_residual(scb); else ahc_set_residual(scb, 0); becomes: ahc_update_residual(scb); Modify scsi parity error (or CRC error) handling to reflect expected phase being disabled on U160 chips. Move SELTO handling above BUSFREE handling so we can use the new busfree interrupt behavior on U160 chips. In ahc_build_transfer_msg() filter the period and ppr_options prior to deciding whether a PPR message is required. ppr_options may be forced to zero which will effect our decision. Correct a long standing but latent bug in ahc_find_syncrate(). We could choose a DT only rate even though DT transfers were disabled. In the CAM environment this was unlikely as CAM filters our rate to a non-DT value if the device does not support such rates. When displaing controller characteristics, include the speed of the chip. This way we can modify the transfer speed based on optional features that are enabled/disabled in a particular application. Add support for switching from fully blown tagged queing to just using simple queue tags should the device reject an ordered tag. Remove per-target "current" disconnect and tag queuing enable flags. These should be per-device and are not referenced internally be the driver, so we let the OSM track this state if it needs to. Use SCSI-3 message terminology. aic7xxx.h: The real 7850 does not support Ultra modes, but there are several cards that use the generic 7850 PCI ID even though they are using an Ultra capable chip (7859/7860). We start out with the AHC_ULTRA feature set and then check the DEVSTATUS register to determine if the capability is really present. current -> curr ahc_calc_residual() is no longer static allowing it to be called from ahc_update_residual() in aic7xxx_inline.h. Update some serial eeprom definitions for the latest BIOS versions. aic7xxx.reg: Add a combined DATA_PHASE mask to the SCSIPHASE register definition to simplify some sequencer code. aic7xxx.seq: Take advantage of some performance features available only on the U160 chips. The auto-ack feature allows us to ack data-in phases up to the data-fifo size while the sequencer is still setting up the DMA engine. This greatly reduces read transfer latency and simplifies testing for transfer complete (check SCSIEN only). We also disable the expected phase feature, and enable the new bus free interrupt behavior, to avoid a few instructions. Re-arrange the Ultra2+ data phase handling to allow us to do more work in parallel with the data fifo flushing on a read. On an SDTR, ack the message immediately so the target can prepare the next phase or message byte in parallel with our work to honor the message. aic7xxx_93cx6.c: Remove linux header ifdefs. aic7xxx_freebsd.c: current -> curr Add a module event handler. Handle tag downgrades in our ahc_send_async() handler. We won't be able to downgrade to "basic queuing" until CAM is made aware of this queuing type. aic7xxx_freebsd.h: Include cleanups. Define offsetof if required. Correct a few comments. Update prototype of ahc_send_async(). aic7xxx_inline.h: Implement ahc_update_residual(). aic7xxx_pci.c: Remove linux header ifdefs. Correct a few product strings. Enable several U160 performance enhancing features. Modify Ultra capability determination so we will enable Ultra speeds on devices with a 7850 PCI id that happen to really be a 7859 or 7860. Don't map our interrupt until after we are fully setup to handle interrupts. Our interrupt line may be shared so an interrupt could occur at any time.
This commit is contained in:
parent
db51613366
commit
3d830a6817
@ -211,3 +211,5 @@ static driver_t ahc_eisa_driver = {
|
||||
static devclass_t ahc_devclass;
|
||||
|
||||
DRIVER_MODULE(ahc, eisa, ahc_eisa_driver, ahc_devclass, 0, 0);
|
||||
MODULE_DEPEND(ahc_eisa, ahc, 1, 1, 1);
|
||||
MODULE_VERSION(ahc_eisa, 1);
|
||||
|
@ -59,6 +59,8 @@ static devclass_t ahc_devclass;
|
||||
|
||||
DRIVER_MODULE(ahc, pci, ahc_pci_driver, ahc_devclass, 0, 0);
|
||||
DRIVER_MODULE(ahc, cardbus, ahc_pci_driver, ahc_devclass, 0, 0);
|
||||
MODULE_DEPEND(ahc_pci, ahc, 1, 1, 1);
|
||||
MODULE_VERSION(ahc_pci, 1);
|
||||
|
||||
static int
|
||||
ahc_pci_probe(device_t dev)
|
||||
|
@ -29,22 +29,14 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/src/aic7xxx/aic7770.c#9 $
|
||||
* $Id: //depot/src/aic7xxx/aic7770.c#11 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
#define ID_AIC7770 0x04907770
|
||||
#define ID_AHA_274x 0x04907771
|
||||
@ -139,10 +131,6 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
|
||||
if ((intdef & EDGE_TRIG) != 0)
|
||||
ahc->flags |= AHC_EDGE_INTERRUPT;
|
||||
|
||||
error = aic7770_map_int(ahc, irq);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
|
||||
case AHC_EISA:
|
||||
{
|
||||
@ -212,6 +200,10 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
|
||||
*/
|
||||
ahc_softc_insert(ahc);
|
||||
|
||||
error = aic7770_map_int(ahc, irq);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Enable the board's BUS drivers
|
||||
*/
|
||||
|
@ -28,22 +28,14 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx.c#35 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx.c#39 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aicasm/aicasm_insformat.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
|
||||
#endif
|
||||
|
||||
/****************************** Softc Data ************************************/
|
||||
struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq);
|
||||
@ -156,6 +148,7 @@ static void ahc_fetch_devinfo(struct ahc_softc *ahc,
|
||||
static void ahc_scb_devinfo(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo,
|
||||
struct scb *scb);
|
||||
static void ahc_assert_atn(struct ahc_softc *ahc);
|
||||
static void ahc_setup_initiator_msgout(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo,
|
||||
struct scb *scb);
|
||||
@ -190,9 +183,11 @@ static void ahc_handle_devreset(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo,
|
||||
cam_status status, char *message,
|
||||
int verbose_level);
|
||||
#if AHC_TARGET_MODE
|
||||
static void ahc_setup_target_msgin(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo,
|
||||
struct scb *scb);
|
||||
#endif
|
||||
|
||||
static bus_dmamap_callback_t ahc_dmamap_cb;
|
||||
static void ahc_build_free_scb_list(struct ahc_softc *ahc);
|
||||
@ -211,7 +206,6 @@ static int ahc_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status);
|
||||
static void ahc_reset_current_bus(struct ahc_softc *ahc);
|
||||
static void ahc_calc_residual(struct scb *scb);
|
||||
#ifdef AHC_DUMP_SEQ
|
||||
static void ahc_dumpseq(struct ahc_softc *ahc);
|
||||
#endif
|
||||
@ -296,7 +290,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
|
||||
|
||||
/*
|
||||
* Clear 32bits of QOUTFIFO at a time
|
||||
* so that we don't clobber an incomming
|
||||
* so that we don't clobber an incoming
|
||||
* byte DMA to the array on architectures
|
||||
* that only support 32bit load and store
|
||||
* operations.
|
||||
@ -319,10 +313,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
|
||||
* Save off the residual
|
||||
* if there is one.
|
||||
*/
|
||||
if (ahc_check_residual(scb) != 0)
|
||||
ahc_calc_residual(scb);
|
||||
else
|
||||
ahc_set_residual(scb, 0);
|
||||
ahc_update_residual(scb);
|
||||
ahc_done(ahc, scb);
|
||||
}
|
||||
}
|
||||
@ -477,16 +468,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
devinfo.our_scsiid,
|
||||
devinfo.target,
|
||||
&tstate);
|
||||
tinfo = &targ_info->current;
|
||||
tinfo = &targ_info->curr;
|
||||
sg = scb->sg_list;
|
||||
sc = (struct scsi_sense *)(&hscb->shared_data.cdb);
|
||||
/*
|
||||
* Save off the residual if there is one.
|
||||
*/
|
||||
if (ahc_check_residual(scb))
|
||||
ahc_calc_residual(scb);
|
||||
else
|
||||
ahc_set_residual(scb, 0);
|
||||
ahc_update_residual(scb);
|
||||
#ifdef AHC_DEBUG
|
||||
if (ahc_debug & AHC_SHOWSENSE) {
|
||||
ahc_print_path(ahc, scb);
|
||||
@ -600,7 +588,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
ahc->msgout_index = 0;
|
||||
ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
|
||||
ahc_outb(ahc, MSG_OUT, HOST_MSG);
|
||||
ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
|
||||
ahc_assert_atn(ahc);
|
||||
break;
|
||||
}
|
||||
case SEND_REJECT:
|
||||
@ -741,17 +729,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
*/
|
||||
if ((intstat & SCSIINT) == 0
|
||||
&& (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) {
|
||||
u_int curphase;
|
||||
|
||||
/*
|
||||
* The hardware will only let you ack bytes
|
||||
* if the expected phase in SCSISIGO matches
|
||||
* the current phase. Make sure this is
|
||||
* currently the case.
|
||||
*/
|
||||
curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
|
||||
ahc_outb(ahc, LASTPHASE, curphase);
|
||||
ahc_outb(ahc, SCSISIGO, curphase);
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
u_int curphase;
|
||||
|
||||
/*
|
||||
* The hardware will only let you ack bytes
|
||||
* if the expected phase in SCSISIGO matches
|
||||
* the current phase. Make sure this is
|
||||
* currently the case.
|
||||
*/
|
||||
curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
|
||||
ahc_outb(ahc, LASTPHASE, curphase);
|
||||
ahc_outb(ahc, SCSISIGO, curphase);
|
||||
}
|
||||
ahc_inb(ahc, SCSIDATL);
|
||||
}
|
||||
break;
|
||||
@ -1042,6 +1033,44 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
|
||||
}
|
||||
ahc_outb(ahc, CLRINT, CLRSCSIINT);
|
||||
ahc_unpause(ahc);
|
||||
} else if ((status & SELTO) != 0) {
|
||||
u_int scbptr;
|
||||
|
||||
/* Stop the selection */
|
||||
ahc_outb(ahc, SCSISEQ, 0);
|
||||
|
||||
/* No more pending messages */
|
||||
ahc_clear_msg_state(ahc);
|
||||
|
||||
/* Clear interrupt state */
|
||||
ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
|
||||
ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
|
||||
|
||||
/*
|
||||
* Although the driver does not care about the
|
||||
* 'Selection in Progress' status bit, the busy
|
||||
* LED does. SELINGO is only cleared by a sucessfull
|
||||
* selection, so we must manually clear it to insure
|
||||
* the LED turns off just incase no future successful
|
||||
* selections occur (e.g. no devices on the bus).
|
||||
*/
|
||||
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);
|
||||
ahc_restart(ahc);
|
||||
} else if ((status & BUSFREE) != 0
|
||||
&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
|
||||
u_int lastphase;
|
||||
@ -1147,7 +1176,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
|
||||
devinfo.our_scsiid,
|
||||
devinfo.target,
|
||||
&tstate);
|
||||
tinfo->current.transport_version = 2;
|
||||
tinfo->curr.transport_version = 2;
|
||||
tinfo->goal.transport_version = 2;
|
||||
tinfo->goal.ppr_options = 0;
|
||||
ahc_qinfifo_requeue_tail(ahc, scb);
|
||||
@ -1209,43 +1238,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
|
||||
ahc_clear_msg_state(ahc);
|
||||
ahc_outb(ahc, CLRINT, CLRSCSIINT);
|
||||
ahc_restart(ahc);
|
||||
} else if ((status & SELTO) != 0) {
|
||||
u_int scbptr;
|
||||
|
||||
/* Stop the selection */
|
||||
ahc_outb(ahc, SCSISEQ, 0);
|
||||
|
||||
/* No more pending messages */
|
||||
ahc_clear_msg_state(ahc);
|
||||
|
||||
/* Clear interrupt state */
|
||||
ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
|
||||
|
||||
/*
|
||||
* Although the driver does not care about the
|
||||
* 'Selection in Progress' status bit, the busy
|
||||
* LED does. SELINGO is only cleared by a sucessful
|
||||
* selection, so we must manually clear it to insure
|
||||
* the LED turns off just incase no future successful
|
||||
* selections occur (e.g. no devices on the bus).
|
||||
*/
|
||||
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);
|
||||
ahc_restart(ahc);
|
||||
} else {
|
||||
printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
|
||||
ahc_name(ahc), status);
|
||||
@ -1418,8 +1410,8 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
|
||||
memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
|
||||
tstate->ultraenb = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
memset(&tstate->transinfo[i].current, 0,
|
||||
sizeof(tstate->transinfo[i].current));
|
||||
memset(&tstate->transinfo[i].curr, 0,
|
||||
sizeof(tstate->transinfo[i].curr));
|
||||
memset(&tstate->transinfo[i].goal, 0,
|
||||
sizeof(tstate->transinfo[i].goal));
|
||||
}
|
||||
@ -1479,8 +1471,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
|
||||
/* Can't do DT on an SE bus */
|
||||
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
||||
}
|
||||
} else if ((ahc->features & AHC_ULTRA) != 0
|
||||
&& (ahc->flags & AHC_ULTRA_DISABLED) == 0) {
|
||||
} else if ((ahc->features & AHC_ULTRA) != 0) {
|
||||
maxsync = AHC_SYNCRATE_ULTRA;
|
||||
} else {
|
||||
maxsync = AHC_SYNCRATE_FAST;
|
||||
@ -1522,6 +1513,11 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
|
||||
if ((ahc->features & AHC_DT) == 0)
|
||||
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
||||
|
||||
/* Skip all DT only entries if DT is not available */
|
||||
if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
|
||||
&& maxsync < AHC_SYNCRATE_ULTRA2)
|
||||
maxsync = AHC_SYNCRATE_ULTRA2;
|
||||
|
||||
for (syncrate = &ahc_syncrates[maxsync];
|
||||
syncrate->rate != NULL;
|
||||
@ -1535,11 +1531,6 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
&& (syncrate->sxfr_u2 == 0))
|
||||
break;
|
||||
|
||||
/* Skip any DT entries if DT is not available */
|
||||
if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
|
||||
&& (syncrate->sxfr_u2 & DT_SXFR) != 0)
|
||||
continue;
|
||||
|
||||
if (*period <= syncrate->period) {
|
||||
/*
|
||||
* When responding to a target that requests
|
||||
@ -1681,10 +1672,10 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
u_int auto_negotiate_orig;
|
||||
|
||||
auto_negotiate_orig = tstate->auto_negotiate;
|
||||
if (tinfo->current.period != tinfo->goal.period
|
||||
|| tinfo->current.width != tinfo->goal.width
|
||||
|| tinfo->current.offset != tinfo->goal.offset
|
||||
|| tinfo->current.ppr_options != tinfo->goal.ppr_options
|
||||
if (tinfo->curr.period != tinfo->goal.period
|
||||
|| tinfo->curr.width != tinfo->goal.width
|
||||
|| tinfo->curr.offset != tinfo->goal.offset
|
||||
|| tinfo->curr.ppr_options != tinfo->goal.ppr_options
|
||||
|| (force
|
||||
&& (tinfo->goal.period != 0
|
||||
|| tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
|
||||
@ -1697,7 +1688,7 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the user/goal/current tables of synchronous negotiation
|
||||
* Update the user/goal/curr tables of synchronous negotiation
|
||||
* parameters as well as, in the case of a current or active update,
|
||||
* any data structures on the host controller. In the case of an
|
||||
* active update, the specified target is currently talking to us on
|
||||
@ -1740,9 +1731,9 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
tinfo->goal.ppr_options = ppr_options;
|
||||
}
|
||||
|
||||
old_period = tinfo->current.period;
|
||||
old_offset = tinfo->current.offset;
|
||||
old_ppr = tinfo->current.ppr_options;
|
||||
old_period = tinfo->curr.period;
|
||||
old_offset = tinfo->curr.offset;
|
||||
old_ppr = tinfo->curr.ppr_options;
|
||||
|
||||
if ((type & AHC_TRANS_CUR) != 0
|
||||
&& (old_period != period
|
||||
@ -1795,12 +1786,12 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
}
|
||||
|
||||
tinfo->scsirate = scsirate;
|
||||
tinfo->current.period = period;
|
||||
tinfo->current.offset = offset;
|
||||
tinfo->current.ppr_options = ppr_options;
|
||||
tinfo->curr.period = period;
|
||||
tinfo->curr.offset = offset;
|
||||
tinfo->curr.ppr_options = ppr_options;
|
||||
|
||||
ahc_send_async(ahc, devinfo->channel, devinfo->target,
|
||||
CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
|
||||
CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
|
||||
if (bootverbose) {
|
||||
if (offset != 0) {
|
||||
printf("%s: target %d synchronous at %sMHz%s, "
|
||||
@ -1824,7 +1815,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the user/goal/current tables of wide negotiation
|
||||
* Update the user/goal/curr tables of wide negotiation
|
||||
* parameters as well as, in the case of a current or active update,
|
||||
* any data structures on the host controller. In the case of an
|
||||
* active update, the specified target is currently talking to us on
|
||||
@ -1852,7 +1843,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
if ((type & AHC_TRANS_GOAL) != 0)
|
||||
tinfo->goal.width = width;
|
||||
|
||||
oldwidth = tinfo->current.width;
|
||||
oldwidth = tinfo->curr.width;
|
||||
if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {
|
||||
u_int scsirate;
|
||||
|
||||
@ -1867,10 +1858,10 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
if (active)
|
||||
ahc_outb(ahc, SCSIRATE, scsirate);
|
||||
|
||||
tinfo->current.width = width;
|
||||
tinfo->curr.width = width;
|
||||
|
||||
ahc_send_async(ahc, devinfo->channel, devinfo->target,
|
||||
CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
|
||||
CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
|
||||
if (bootverbose) {
|
||||
printf("%s: target %d using %dbit transfers\n",
|
||||
ahc_name(ahc), devinfo->target,
|
||||
@ -1888,27 +1879,12 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
* Update the current state of tagged queuing for a given target.
|
||||
*/
|
||||
void
|
||||
ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable)
|
||||
ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
ahc_queue_alg alg)
|
||||
{
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
uint16_t orig_tagenable;
|
||||
|
||||
tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
|
||||
devinfo->target, &tstate);
|
||||
|
||||
orig_tagenable = tstate->tagenable;
|
||||
if (enable)
|
||||
tstate->tagenable |= devinfo->target_mask;
|
||||
else
|
||||
tstate->tagenable &= ~devinfo->target_mask;
|
||||
|
||||
if (orig_tagenable != tstate->tagenable) {
|
||||
ahc_platform_set_tags(ahc, devinfo, enable);
|
||||
ahc_send_async(ahc, devinfo->channel, devinfo->target,
|
||||
devinfo->lun, AC_TRANSFER_NEG);
|
||||
}
|
||||
|
||||
ahc_platform_set_tags(ahc, devinfo, alg);
|
||||
ahc_send_async(ahc, devinfo->channel, devinfo->target,
|
||||
devinfo->lun, AC_TRANSFER_NEG, &alg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1945,7 +1921,7 @@ ahc_update_pending_scbs(struct ahc_softc *ahc)
|
||||
if ((tstate->ultraenb & devinfo.target_mask) != 0)
|
||||
pending_hscb->control |= ULTRAENB;
|
||||
pending_hscb->scsirate = tinfo->scsirate;
|
||||
pending_hscb->scsioffset = tinfo->current.offset;
|
||||
pending_hscb->scsioffset = tinfo->curr.offset;
|
||||
if ((tstate->auto_negotiate & devinfo.target_mask) == 0
|
||||
&& (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {
|
||||
pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
|
||||
@ -2073,6 +2049,17 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
|
||||
|
||||
/************************ Message Phase Processing ****************************/
|
||||
static void
|
||||
ahc_assert_atn(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int scsisigo;
|
||||
|
||||
scsisigo = ATNO;
|
||||
if ((ahc->features & AHC_DT) == 0)
|
||||
scsisigo |= ahc_inb(ahc, SCSISIGI);
|
||||
ahc_outb(ahc, SCSISIGO, scsisigo);
|
||||
}
|
||||
|
||||
/*
|
||||
* When an initiator transaction with the MK_MESSAGE flag either reconnects
|
||||
* or enters the initial message out phase, we are interrupted. Fill our
|
||||
@ -2186,9 +2173,19 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
|
||||
tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
|
||||
devinfo->target, &tstate);
|
||||
dowide = tinfo->current.width != tinfo->goal.width;
|
||||
dosync = tinfo->current.period != tinfo->goal.period;
|
||||
doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options;
|
||||
/*
|
||||
* Filter our period based on the current connection.
|
||||
* If we can't perform DT transfers on this segment (not in LVD
|
||||
* mode for instance), then our decision to issue a PPR message
|
||||
* may change.
|
||||
*/
|
||||
period = tinfo->goal.period;
|
||||
ppr_options = tinfo->goal.ppr_options;
|
||||
rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
|
||||
&ppr_options, devinfo->role);
|
||||
dowide = tinfo->curr.width != tinfo->goal.width;
|
||||
dosync = tinfo->curr.period != period;
|
||||
doppr = tinfo->curr.ppr_options != ppr_options;
|
||||
|
||||
if (!dowide && !dosync && !doppr) {
|
||||
dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
|
||||
@ -2201,7 +2198,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
"but no negotiation needed\n");
|
||||
}
|
||||
|
||||
use_ppr = (tinfo->current.transport_version >= 3) || doppr;
|
||||
use_ppr = (tinfo->curr.transport_version >= 3) || doppr;
|
||||
/* Target initiated PPR is not allowed in the SCSI spec */
|
||||
if (devinfo->role == ROLE_TARGET)
|
||||
use_ppr = 0;
|
||||
@ -2216,16 +2213,10 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
*/
|
||||
if (use_ppr || (dosync && !dowide)) {
|
||||
|
||||
period = tinfo->goal.period;
|
||||
ppr_options = tinfo->goal.ppr_options;
|
||||
if (use_ppr == 0)
|
||||
ppr_options = 0;
|
||||
rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
|
||||
&ppr_options, devinfo->role);
|
||||
offset = tinfo->goal.offset;
|
||||
ahc_validate_offset(ahc, tinfo, rate, &offset,
|
||||
use_ppr ? tinfo->goal.width
|
||||
: tinfo->current.width,
|
||||
: tinfo->curr.width,
|
||||
devinfo->role);
|
||||
if (use_ppr) {
|
||||
ahc_construct_ppr(ahc, devinfo, period, offset,
|
||||
@ -2383,7 +2374,7 @@ ahc_handle_message_phase(struct ahc_softc *ahc)
|
||||
* 0, and try again.
|
||||
*/
|
||||
ahc->msgout_index = 0;
|
||||
ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
|
||||
ahc_assert_atn(ahc);
|
||||
}
|
||||
|
||||
lastbyte = ahc->msgout_index == (ahc->msgout_len - 1);
|
||||
@ -2438,8 +2429,7 @@ ahc_handle_message_phase(struct ahc_softc *ahc)
|
||||
* message out phase.
|
||||
*/
|
||||
if (ahc->msgout_len != 0)
|
||||
ahc_outb(ahc, SCSISIGO,
|
||||
ahc_inb(ahc, SCSISIGO) | ATNO);
|
||||
ahc_assert_atn(ahc);
|
||||
} else
|
||||
ahc->msgin_index++;
|
||||
|
||||
@ -2604,7 +2594,7 @@ ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full)
|
||||
found = TRUE;
|
||||
}
|
||||
index = end_index;
|
||||
} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
|
||||
} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK
|
||||
&& ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
|
||||
|
||||
/* Skip tag type and tag id or residue param*/
|
||||
@ -2625,7 +2615,7 @@ ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full)
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for a complete incomming message, parse it, and respond accordingly.
|
||||
* Wait for a complete incoming message, parse it, and respond accordingly.
|
||||
*/
|
||||
static int
|
||||
ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
@ -3062,7 +3052,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
devinfo->target, devinfo->lun);
|
||||
}
|
||||
tinfo->goal.ppr_options = 0;
|
||||
tinfo->current.transport_version = 2;
|
||||
tinfo->curr.transport_version = 2;
|
||||
tinfo->goal.transport_version = 2;
|
||||
ahc->msgout_index = 0;
|
||||
ahc->msgout_len = 0;
|
||||
@ -3104,24 +3094,39 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
"Using asynchronous transfers\n",
|
||||
ahc_name(ahc), devinfo->channel,
|
||||
devinfo->target, devinfo->lun);
|
||||
} else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) {
|
||||
} else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) {
|
||||
int tag_type;
|
||||
int mask;
|
||||
|
||||
printf("(%s:%c:%d:%d): refuses tagged commands. Performing "
|
||||
"non-tagged I/O\n", ahc_name(ahc),
|
||||
devinfo->channel, devinfo->target, devinfo->lun);
|
||||
ahc_set_tags(ahc, devinfo, FALSE);
|
||||
tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
|
||||
|
||||
if (tag_type == MSG_SIMPLE_TASK) {
|
||||
printf("(%s:%c:%d:%d): refuses tagged commands. "
|
||||
"Performing non-tagged I/O\n", ahc_name(ahc),
|
||||
devinfo->channel, devinfo->target, devinfo->lun);
|
||||
ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE);
|
||||
mask = ~0x23;
|
||||
} else {
|
||||
printf("(%s:%c:%d:%d): refuses %s tagged commands. "
|
||||
"Performing simple queue tagged I/O only\n",
|
||||
ahc_name(ahc), devinfo->channel, devinfo->target,
|
||||
devinfo->lun, tag_type == MSG_ORDERED_TASK
|
||||
? "ordered" : "head of queue");
|
||||
ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC);
|
||||
mask = ~0x03;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resend the identify for this CCB as the target
|
||||
* may believe that the selection is invalid otherwise.
|
||||
*/
|
||||
ahc_outb(ahc, SCB_CONTROL,
|
||||
ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG);
|
||||
scb->hscb->control &= ~MSG_SIMPLE_Q_TAG;
|
||||
ahc_inb(ahc, SCB_CONTROL) & mask);
|
||||
scb->hscb->control &= mask;
|
||||
ahc_set_transaction_tag(scb, /*enabled*/FALSE,
|
||||
/*type*/MSG_SIMPLE_Q_TAG);
|
||||
/*type*/MSG_SIMPLE_TASK);
|
||||
ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG);
|
||||
ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
|
||||
ahc_assert_atn(ahc);
|
||||
|
||||
/*
|
||||
* This transaction is now at the head of
|
||||
@ -3323,7 +3328,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
AHC_TRANS_CUR, /*paused*/TRUE);
|
||||
|
||||
ahc_send_async(ahc, devinfo->channel, devinfo->target,
|
||||
CAM_LUN_WILDCARD, AC_SENT_BDR);
|
||||
CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
|
||||
|
||||
if (message != NULL
|
||||
&& (verbose_level <= bootverbose))
|
||||
@ -4032,15 +4037,24 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf)
|
||||
ahc->our_id, ahc->our_id_b,
|
||||
(ahc->flags & AHC_PRIMARY_CHANNEL) + 'A');
|
||||
else {
|
||||
const char *speed;
|
||||
const char *type;
|
||||
|
||||
speed = "";
|
||||
if ((ahc->features & AHC_ULTRA) != 0) {
|
||||
speed = "Ultra ";
|
||||
} else if ((ahc->features & AHC_DT) != 0) {
|
||||
speed = "Ultra160 ";
|
||||
} else if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
speed = "Ultra2 ";
|
||||
}
|
||||
if ((ahc->features & AHC_WIDE) != 0) {
|
||||
type = "Wide";
|
||||
} else {
|
||||
type = "Single";
|
||||
}
|
||||
len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ",
|
||||
type, ahc->channel, ahc->our_id);
|
||||
len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ",
|
||||
speed, type, ahc->channel, ahc->our_id);
|
||||
}
|
||||
buf += len;
|
||||
|
||||
@ -4292,8 +4306,6 @@ ahc_init(struct ahc_softc *ahc)
|
||||
ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8)
|
||||
| ahc_inb(ahc, ULTRA_ENB);
|
||||
}
|
||||
if ((ahc->flags & AHC_ULTRA_DISABLED) != 0)
|
||||
ultraenb = 0;
|
||||
|
||||
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
|
||||
max_targ = 7;
|
||||
@ -4393,12 +4405,10 @@ ahc_init(struct ahc_softc *ahc)
|
||||
tinfo->user.transport_version = 2;
|
||||
tinfo->goal.protocol_version = 2;
|
||||
tinfo->goal.transport_version = 2;
|
||||
tinfo->current.protocol_version = 2;
|
||||
tinfo->current.transport_version = 2;
|
||||
tinfo->curr.protocol_version = 2;
|
||||
tinfo->curr.transport_version = 2;
|
||||
}
|
||||
tstate->ultraenb = ultraenb;
|
||||
tstate->discenable = discenable;
|
||||
tstate->tagenable = 0; /* Wait until the XPT says its okay */
|
||||
}
|
||||
ahc->user_discenable = discenable;
|
||||
ahc->user_tagenable = tagenable;
|
||||
@ -5430,7 +5440,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
|
||||
* Go through the pending CCB list and look for
|
||||
* commands for this target that are still active.
|
||||
* These are other tagged commands that were
|
||||
* disconnected when the reset occured.
|
||||
* disconnected when the reset occurred.
|
||||
*/
|
||||
scbp_next = LIST_FIRST(&ahc->pending_scbs);
|
||||
while (scbp_next != NULL) {
|
||||
@ -5581,7 +5591,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
|
||||
#endif
|
||||
/* Notify the XPT that a bus reset occurred */
|
||||
ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
|
||||
CAM_LUN_WILDCARD, AC_BUS_RESET);
|
||||
CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
|
||||
|
||||
/*
|
||||
* Revert to async/narrow transfers until we renegotiate.
|
||||
@ -5617,7 +5627,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
|
||||
/*
|
||||
* Calculate the residual for a just completed SCB.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
ahc_calc_residual(struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
@ -6632,7 +6642,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
|
||||
cmd->cmd_valid = 0;
|
||||
|
||||
/*
|
||||
* Lazily update our position in the target mode incomming
|
||||
* Lazily update our position in the target mode incoming
|
||||
* command queue as seen by the sequencer.
|
||||
*/
|
||||
if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
|
||||
|
@ -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#24 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx.h#27 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -209,9 +209,15 @@ typedef enum {
|
||||
AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */
|
||||
AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */
|
||||
AHC_AIC7770_FE = AHC_FENONE,
|
||||
AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE,
|
||||
AHC_AIC7855_FE = AHC_AIC7850_FE,
|
||||
AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA,
|
||||
/*
|
||||
* The real 7850 does not support Ultra modes, but there are
|
||||
* several cards that use the generic 7850 PCI ID even though
|
||||
* they are using an Ultra capable chip (7859/7860). We start
|
||||
* out with the AHC_ULTRA feature set and then check the DEVSTATUS
|
||||
* register to determine if the capability is really present.
|
||||
*/
|
||||
AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA,
|
||||
AHC_AIC7860_FE = AHC_AIC7850_FE,
|
||||
AHC_AIC7870_FE = AHC_TARGETMODE,
|
||||
AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA,
|
||||
/*
|
||||
@ -328,12 +334,6 @@ typedef enum {
|
||||
*/
|
||||
AHC_BIOS_ENABLED = 0x80000,
|
||||
AHC_ALL_INTERRUPTS = 0x100000,
|
||||
AHC_ULTRA_DISABLED = 0x200000, /*
|
||||
* The precision resistor for
|
||||
* ultra transmission speeds is
|
||||
* missing, so we must limit
|
||||
* ourselves to fast SCSI.
|
||||
*/
|
||||
AHC_PAGESCBS = 0x400000, /* Enable SCB paging */
|
||||
AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */
|
||||
} ahc_flag;
|
||||
@ -660,7 +660,7 @@ struct ahc_transinfo {
|
||||
* Per-initiator current, goal and user transfer negotiation information. */
|
||||
struct ahc_initiator_tinfo {
|
||||
uint8_t scsirate; /* Computed value for SCSIRATE reg */
|
||||
struct ahc_transinfo current;
|
||||
struct ahc_transinfo curr;
|
||||
struct ahc_transinfo goal;
|
||||
struct ahc_transinfo user;
|
||||
};
|
||||
@ -749,12 +749,19 @@ struct seeprom_config {
|
||||
#define CFSUPREM 0x0001 /* support all removeable drives */
|
||||
#define CFSUPREMB 0x0002 /* support removeable boot drives */
|
||||
#define CFBIOSEN 0x0004 /* BIOS enabled */
|
||||
/* UNUSED 0x0008 */
|
||||
#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */
|
||||
#define CFSM2DRV 0x0010 /* support more than two drives */
|
||||
#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
|
||||
#define CFSTPWLEVEL 0x0010 /* Termination level control */
|
||||
#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
|
||||
#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */
|
||||
#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */
|
||||
#define CFEXTEND 0x0080 /* extended translation enabled */
|
||||
#define CFSCAMEN 0x0100 /* SCAM enable */
|
||||
#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */
|
||||
#define CFMSG_VERBOSE 0x0000
|
||||
#define CFMSG_SILENT 0x0200
|
||||
#define CFMSG_DIAG 0x0400
|
||||
#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */
|
||||
/* UNUSED 0xff00 */
|
||||
|
||||
/*
|
||||
@ -769,7 +776,7 @@ struct seeprom_config {
|
||||
#define CFWSTERM 0x0008 /* SCSI high byte termination */
|
||||
#define CFSPARITY 0x0010 /* SCSI parity */
|
||||
#define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */
|
||||
#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */
|
||||
#define CFMULTILUN 0x0020
|
||||
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
|
||||
#define CFCLUSTERENB 0x0080 /* Cluster Enable */
|
||||
#define CFBOOTCHAN 0x0300 /* probe this channel first */
|
||||
@ -1135,6 +1142,7 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
|
||||
int ahc_reset_channel(struct ahc_softc *ahc, char channel,
|
||||
int initiate_reset);
|
||||
void ahc_restart(struct ahc_softc *ahc);
|
||||
void ahc_calc_residual(struct scb *scb);
|
||||
/*************************** Utility Functions ********************************/
|
||||
struct ahc_phase_table_entry*
|
||||
ahc_lookup_phase_entry(int phase);
|
||||
@ -1170,8 +1178,15 @@ void ahc_set_syncrate(struct ahc_softc *ahc,
|
||||
u_int period, u_int offset,
|
||||
u_int ppr_options,
|
||||
u_int type, int paused);
|
||||
typedef enum {
|
||||
AHC_QUEUE_NONE,
|
||||
AHC_QUEUE_BASIC,
|
||||
AHC_QUEUE_TAGGED
|
||||
} ahc_queue_alg;
|
||||
|
||||
void ahc_set_tags(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo, int enable);
|
||||
struct ahc_devinfo *devinfo,
|
||||
ahc_queue_alg alg);
|
||||
|
||||
/**************************** Target Mode *************************************/
|
||||
#ifdef AHC_TARGET_MODE
|
||||
|
@ -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#15 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -970,6 +970,7 @@ register SCSIPHASE {
|
||||
bit MSG_OUT_PHASE 0x04
|
||||
bit DATA_IN_PHASE 0x02
|
||||
bit DATA_OUT_PHASE 0x01
|
||||
mask DATA_PHASE_MASK 0x03
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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#24 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -153,7 +153,9 @@ selection:
|
||||
* the kernel driver if it happens.
|
||||
*/
|
||||
mvi CLRSINT1,CLRBUSFREE;
|
||||
or SIMODE1, ENBUSFREE;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
or SIMODE1, ENBUSFREE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against a bus free after (re)selection
|
||||
@ -706,17 +708,17 @@ disable_ccsgen_fetch_done:
|
||||
test CCSGCTL, CCSGEN jnz .;
|
||||
ret;
|
||||
idle_loop:
|
||||
/*
|
||||
* Do we need any more segments for this transfer?
|
||||
*/
|
||||
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
|
||||
|
||||
/* Did we just finish fetching segs? */
|
||||
cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
|
||||
|
||||
/* Are we actively fetching segments? */
|
||||
test CCSGCTL, CCSGEN jnz return;
|
||||
|
||||
/*
|
||||
* Do we need any more segments?
|
||||
*/
|
||||
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
|
||||
|
||||
/*
|
||||
* Do we have any prefetch left???
|
||||
*/
|
||||
@ -885,7 +887,11 @@ data_phase_loop:
|
||||
and DMAPARAMS, DIRECTION;
|
||||
mov DFCNTRL, DMAPARAMS;
|
||||
or SXFRCTL1,BITBUCKET;
|
||||
test SSTAT1,PHASEMIS jz .;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
test SSTAT1,PHASEMIS jz .;
|
||||
} else {
|
||||
test SCSIPHASE, DATA_PHASE_MASK jnz .;
|
||||
}
|
||||
and SXFRCTL1, ~BITBUCKET;
|
||||
mvi DATA_OVERRUN call set_seqint;
|
||||
jmp ITloop;
|
||||
@ -906,54 +912,48 @@ ultra2_dma_loop:
|
||||
* completes or the target changes phase.
|
||||
*/
|
||||
test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
/*
|
||||
* As a target, we control the phases,
|
||||
* so ignore PHASEMIS.
|
||||
*/
|
||||
test SSTAT0, TARGET jnz ultra2_dma_loop;
|
||||
}
|
||||
if ((ahc->flags & AHC_INITIATORROLE) != 0) {
|
||||
test SSTAT1,PHASEMIS jz ultra2_dma_loop;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
/*
|
||||
* As a target, we control the phases,
|
||||
* so ignore PHASEMIS.
|
||||
*/
|
||||
test SSTAT0, TARGET jnz ultra2_dma_loop;
|
||||
}
|
||||
if ((ahc->flags & AHC_INITIATORROLE) != 0) {
|
||||
test SSTAT1,PHASEMIS jz ultra2_dma_loop;
|
||||
}
|
||||
} else {
|
||||
test DFCNTRL, SCSIEN jnz ultra2_dma_loop;
|
||||
}
|
||||
|
||||
ultra2_dmafinish:
|
||||
test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
and DFCNTRL, ~SCSIEN;
|
||||
test DFCNTRL, SCSIEN jnz .;
|
||||
}
|
||||
ultra2_dmafifoflush:
|
||||
/*
|
||||
* The transfer has terminated either due to a phase
|
||||
* change, and/or the completion of the last segment.
|
||||
* We have two goals here. Do as much other work
|
||||
* as possible while the data fifo drains on a read
|
||||
* and respond as quickly as possible to the standard
|
||||
* messages (save data pointers/disconnect and command
|
||||
* complete) that usually follow a data phase.
|
||||
*/
|
||||
if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
|
||||
/*
|
||||
* On Rev A of the aic7890, the autoflush
|
||||
* features doesn't function correctly.
|
||||
* Perform an explicit manual flush. During
|
||||
* a manual flush, the FIFOEMP bit becomes
|
||||
* true every time the PCI FIFO empties
|
||||
* regardless of the state of the SCSI FIFO.
|
||||
* It can take up to 4 clock cycles for the
|
||||
* SCSI FIFO to get data into the PCI FIFO
|
||||
* and for FIFOEMP to de-assert. Here we
|
||||
* guard against this condition by making
|
||||
* sure the FIFOEMP bit stays on for 5 full
|
||||
* clock cycles.
|
||||
* On chips with broken auto-flush, start
|
||||
* the flushing process now. We'll poke
|
||||
* the chip from time to time to keep the
|
||||
* flush process going as we complete the
|
||||
* data phase.
|
||||
*/
|
||||
or DFCNTRL, FIFOFLUSH;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
|
||||
}
|
||||
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
|
||||
ultra2_dmafifoempty:
|
||||
/* Don't clobber an inprogress host data transfer */
|
||||
test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty;
|
||||
ultra2_dmahalt:
|
||||
and DFCNTRL, ~(SCSIEN|HDMAEN);
|
||||
test DFCNTRL, SCSIEN|HDMAEN jnz .;
|
||||
|
||||
/*
|
||||
* We assume that, even though data may still be
|
||||
* transferring to the host, that the SCSI side of
|
||||
* the DMA engine is now in a static state. This
|
||||
* allows us to update our notion of where we are
|
||||
* in this transfer.
|
||||
*
|
||||
* If, by chance, we stopped before being able
|
||||
* to fetch additional segments for this transfer,
|
||||
* yet the last S/G was completely exhausted,
|
||||
@ -964,14 +964,14 @@ ultra2_dmahalt:
|
||||
* If we happened to stop on the last segment, then
|
||||
* our residual information is still correct from
|
||||
* the idle loop and there is no need to perform
|
||||
* any fixups. Just jump to data_phase_finish.
|
||||
* any fixups.
|
||||
*/
|
||||
ultra2_ensure_sg:
|
||||
test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
|
||||
/* Record if we've consumed all S/G entries */
|
||||
test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish;
|
||||
test SSTAT2, SHVALID jnz residuals_correct;
|
||||
or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
|
||||
jmp data_phase_finish;
|
||||
jmp residuals_correct;
|
||||
|
||||
ultra2_shvalid:
|
||||
test SSTAT2, SHVALID jnz sgptr_fixup;
|
||||
@ -1001,6 +1001,62 @@ sgptr_fixup_done:
|
||||
test SG_CACHE_SHADOW, ODD_SEG jz . + 2;
|
||||
or DATA_COUNT_ODD, 0x1;
|
||||
clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
|
||||
residuals_correct:
|
||||
/*
|
||||
* Go ahead and shut down the DMA engine now.
|
||||
* In the future, we'll want to handle end of
|
||||
* transfer messages prior to doing this, but this
|
||||
* requires similar restructuring for pre-ULTRA2
|
||||
* controllers.
|
||||
*/
|
||||
test DMAPARAMS, DIRECTION jnz ultra2_fifoempty;
|
||||
ultra2_fifoflush:
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
|
||||
/*
|
||||
* On Rev A of the aic7890, the autoflush
|
||||
* feature doesn't function correctly.
|
||||
* Perform an explicit manual flush. During
|
||||
* a manual flush, the FIFOEMP bit becomes
|
||||
* true every time the PCI FIFO empties
|
||||
* regardless of the state of the SCSI FIFO.
|
||||
* It can take up to 4 clock cycles for the
|
||||
* SCSI FIFO to get data into the PCI FIFO
|
||||
* and for FIFOEMP to de-assert. Here we
|
||||
* guard against this condition by making
|
||||
* sure the FIFOEMP bit stays on for 5 full
|
||||
* clock cycles.
|
||||
*/
|
||||
or DFCNTRL, FIFOFLUSH;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_fifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_fifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_fifoflush;
|
||||
test DFSTATUS, FIFOEMP jz ultra2_fifoflush;
|
||||
}
|
||||
test DFSTATUS, FIFOEMP jz ultra2_fifoflush;
|
||||
} else {
|
||||
/*
|
||||
* We enable the auto-ack feature on DT capable
|
||||
* controllers. This means that the controller may
|
||||
* have already transferred some overrun bytes into
|
||||
* the data FIFO and acked them on the bus. The only
|
||||
* way to detect this situation is to wait for
|
||||
* LAST_SEG_DONE to come true on a completed transfer
|
||||
* and then test to see if the data FIFO is non-empty.
|
||||
*/
|
||||
test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4;
|
||||
test SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
|
||||
test DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
|
||||
/* Overrun */
|
||||
jmp data_phase_loop;
|
||||
test DFSTATUS, FIFOEMP jz .;
|
||||
}
|
||||
ultra2_fifoempty:
|
||||
/* Don't clobber an inprogress host data transfer */
|
||||
test DFSTATUS, MREQPEND jnz ultra2_fifoempty;
|
||||
ultra2_dmahalt:
|
||||
and DFCNTRL, ~(SCSIEN|HDMAEN);
|
||||
test DFCNTRL, SCSIEN|HDMAEN jnz .;
|
||||
} else {
|
||||
/* If we are the last SG block, tell the hardware. */
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
|
||||
@ -1159,7 +1215,11 @@ data_phase_finish:
|
||||
}
|
||||
if ((ahc->flags & AHC_INITIATORROLE) != 0) {
|
||||
test SSTAT1, REQINIT jz .;
|
||||
test SSTAT1,PHASEMIS jz data_phase_loop;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
test SSTAT1,PHASEMIS jz data_phase_loop;
|
||||
} else {
|
||||
test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop;
|
||||
}
|
||||
}
|
||||
|
||||
data_phase_done:
|
||||
@ -1263,7 +1323,7 @@ p_command_from_host:
|
||||
jmp p_command_loop;
|
||||
p_command_embedded:
|
||||
/*
|
||||
* The data fifo seems to require 4 byte alligned
|
||||
* The data fifo seems to require 4 byte aligned
|
||||
* transfers from the sequencer. Force this to
|
||||
* be the case by clearing HADDR[0] even though
|
||||
* we aren't going to touch host memeory.
|
||||
@ -1299,13 +1359,17 @@ p_command_embedded:
|
||||
or DFCNTRL, FIFOFLUSH;
|
||||
}
|
||||
p_command_loop:
|
||||
test SSTAT0, SDONE jnz . + 2;
|
||||
test SSTAT1, PHASEMIS jz p_command_loop;
|
||||
/*
|
||||
* Wait for our ACK to go-away on it's own
|
||||
* instead of being killed by SCSIEN getting cleared.
|
||||
*/
|
||||
test SCSISIGI, ACKI jnz .;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
test SSTAT0, SDONE jnz . + 2;
|
||||
test SSTAT1, PHASEMIS jz p_command_loop;
|
||||
/*
|
||||
* Wait for our ACK to go-away on it's own
|
||||
* instead of being killed by SCSIEN getting cleared.
|
||||
*/
|
||||
test SCSISIGI, ACKI jnz .;
|
||||
} else {
|
||||
test DFCNTRL, SCSIEN jnz p_command_loop;
|
||||
}
|
||||
and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
|
||||
test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
@ -1349,7 +1413,12 @@ p_status:
|
||||
* reason.
|
||||
*/
|
||||
p_mesgout_retry:
|
||||
or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
|
||||
/* Turn on ATN for the retry */
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
or SCSISIGO, ATNO, LASTPHASE;
|
||||
} else {
|
||||
mvi SCSISIGO, ATNO;
|
||||
}
|
||||
p_mesgout:
|
||||
mov SINDEX, MSG_OUT;
|
||||
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
|
||||
@ -1546,10 +1615,17 @@ mesgin_disconnect:
|
||||
* only if we've actually been into a data phase to change them. This
|
||||
* protects against bogus data in scratch ram and the residual counts
|
||||
* since they are only initialized when we go into data_in or data_out.
|
||||
* Ack the message as soon as possible. For chips without S/G pipelining,
|
||||
* we can only ack the message after SHADDR has been saved. On these
|
||||
* chips, SHADDR increments with every bus transaction, even PIO.
|
||||
*/
|
||||
mesgin_sdptrs:
|
||||
test SEQ_FLAGS, DPHASE jz mesgin_done;
|
||||
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
|
||||
test SEQ_FLAGS, DPHASE jz ITloop;
|
||||
} else {
|
||||
test SEQ_FLAGS, DPHASE jz mesgin_done;
|
||||
}
|
||||
/*
|
||||
* The SCB_SGPTR becomes the next one we'll download,
|
||||
* and the SCB_DATAPTR becomes the current SHADDR.
|
||||
@ -1558,13 +1634,17 @@ mesgin_sdptrs:
|
||||
*/
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov SCB_DATAPTR, SHADDR, 4;
|
||||
if ((ahc->features & AHC_ULTRA2) == 0) {
|
||||
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
|
||||
}
|
||||
bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
|
||||
} else {
|
||||
mvi DINDEX, SCB_DATAPTR;
|
||||
mvi SHADDR call bcopy_4;
|
||||
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
|
||||
mvi SCB_RESIDUAL_DATACNT call bcopy_8;
|
||||
}
|
||||
jmp mesgin_done;
|
||||
jmp ITloop;
|
||||
|
||||
/*
|
||||
* Restore pointers message? Data pointers are recopied from the
|
||||
@ -1742,7 +1822,11 @@ not_found:
|
||||
jmp mesgin_done;
|
||||
|
||||
mk_mesg:
|
||||
or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
or SCSISIGO, ATNO, LASTPHASE;
|
||||
} else {
|
||||
mvi SCSISIGO, ATNO;
|
||||
}
|
||||
mov MSG_OUT,SINDEX ret;
|
||||
|
||||
/*
|
||||
@ -1789,7 +1873,7 @@ if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
* from out to in, wait an additional data release delay before continuing.
|
||||
*/
|
||||
change_phase:
|
||||
/* Wait for preceding I/O session to complete. */
|
||||
/* Wait for preceeding I/O session to complete. */
|
||||
test SCSISIGI, ACKI jnz .;
|
||||
|
||||
/* Change the phase */
|
||||
@ -1915,7 +1999,9 @@ phase_lock:
|
||||
test SSTAT1, REQINIT jz phase_lock;
|
||||
test SSTAT1, SCSIPERR jnz phase_lock_perr;
|
||||
phase_lock_latch_phase:
|
||||
and SCSISIGO, PHASE_MASK, SCSISIGI;
|
||||
if ((ahc->features & AHC_DT) == 0) {
|
||||
and SCSISIGO, PHASE_MASK, SCSISIGI;
|
||||
}
|
||||
and LASTPHASE, PHASE_MASK, SCSISIGI ret;
|
||||
|
||||
if ((ahc->features & AHC_CMD_CHAN) == 0) {
|
||||
|
@ -67,17 +67,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Right now, we only have to read the SEEPROM. But we make it easier to
|
||||
|
@ -49,6 +49,7 @@ static int ahc_debug = AHC_DEBUG;
|
||||
#if UNUSED
|
||||
static void ahc_dump_targcmd(struct target_cmd *cmd);
|
||||
#endif
|
||||
static int ahc_modevent(module_t mod, int type, void *data);
|
||||
static void ahc_action(struct cam_sim *sim, union ccb *ccb);
|
||||
static void ahc_get_tran_settings(struct ahc_softc *ahc,
|
||||
int our_id, char channel,
|
||||
@ -572,9 +573,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
|
||||
update_type |= AHC_TRANS_GOAL;
|
||||
discenable = &tstate->discenable;
|
||||
tagenable = &tstate->tagenable;
|
||||
tinfo->current.protocol_version =
|
||||
tinfo->curr.protocol_version =
|
||||
cts->protocol_version;
|
||||
tinfo->current.transport_version =
|
||||
tinfo->curr.transport_version =
|
||||
cts->transport_version;
|
||||
tinfo->goal.protocol_version =
|
||||
cts->protocol_version;
|
||||
@ -777,7 +778,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
|
||||
&& tinfo->user.transport_version >= 3) {
|
||||
tinfo->goal.transport_version =
|
||||
tinfo->user.transport_version;
|
||||
tinfo->current.transport_version =
|
||||
tinfo->curr.transport_version =
|
||||
tinfo->user.transport_version;
|
||||
}
|
||||
|
||||
@ -932,7 +933,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
|
||||
devinfo.target, &tstate);
|
||||
|
||||
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
||||
tinfo = &targ_info->current;
|
||||
tinfo = &targ_info->curr;
|
||||
else
|
||||
tinfo = &targ_info->user;
|
||||
|
||||
@ -990,7 +991,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
|
||||
devinfo.target, &tstate);
|
||||
|
||||
if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
|
||||
tinfo = &targ_info->current;
|
||||
tinfo = &targ_info->curr;
|
||||
else
|
||||
tinfo = &targ_info->user;
|
||||
|
||||
@ -1206,7 +1207,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
|
||||
mask = SCB_GET_TARGET_MASK(ahc, scb);
|
||||
scb->hscb->scsirate = tinfo->scsirate;
|
||||
scb->hscb->scsioffset = tinfo->current.offset;
|
||||
scb->hscb->scsioffset = tinfo->curr.offset;
|
||||
if ((tstate->ultraenb & mask) != 0)
|
||||
scb->hscb->control |= ULTRAENB;
|
||||
|
||||
@ -1767,7 +1768,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
|
||||
void
|
||||
ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
u_int lun, ac_code code)
|
||||
u_int lun, ac_code code, void *opt_arg)
|
||||
{
|
||||
struct ccb_trans_settings cts;
|
||||
struct cam_path *path;
|
||||
@ -1782,8 +1783,12 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
|
||||
switch (code) {
|
||||
case AC_TRANSFER_NEG:
|
||||
{
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
struct ccb_trans_settings_scsi *scsi;
|
||||
|
||||
cts.type = CTS_TYPE_CURRENT_SETTINGS;
|
||||
scsi = &cts.proto_specific.scsi;
|
||||
#else
|
||||
cts.flags = CCB_TRANS_CURRENT_SETTINGS;
|
||||
#endif
|
||||
@ -1794,7 +1799,25 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
: ahc->our_id_b,
|
||||
channel, &cts);
|
||||
arg = &cts;
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
scsi->valid &= ~CTS_SCSI_VALID_TQ;
|
||||
scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
|
||||
#else
|
||||
cts.valid &= ~CCB_TRANS_TQ_VALID;
|
||||
cts.flags &= ~CCB_TRANS_TAG_ENB;
|
||||
#endif
|
||||
if (opt_arg == NULL)
|
||||
break;
|
||||
if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED)
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
|
||||
scsi->valid |= CTS_SCSI_VALID_TQ;
|
||||
#else
|
||||
cts.flags |= CCB_TRANS_TAG_ENB;
|
||||
cts.valid |= CCB_TRANS_TQ_VALID;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case AC_SENT_BDR:
|
||||
case AC_BUS_RESET:
|
||||
break;
|
||||
@ -1906,3 +1929,20 @@ ahc_dump_targcmd(struct target_cmd *cmd)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ahc_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
/* XXX Deal with busy status on unload. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static moduledata_t ahc_mod = {
|
||||
"ahc",
|
||||
ahc_modevent,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
|
||||
MODULE_DEPEND(ahc, cam, 1, 1, 1);
|
||||
MODULE_VERSION(ahc, 1);
|
||||
|
@ -41,7 +41,9 @@
|
||||
#define AHC_NEW_TRAN_SETTINGS
|
||||
#endif /* CAM_NEW_TRAN_CODE */
|
||||
#include <opt_aic7xxx.h> /* for config options */
|
||||
#include <pci.h> /* for NPCI */
|
||||
#ifndef NPCI
|
||||
#include <pci.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -96,6 +98,9 @@
|
||||
(SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \
|
||||
: (ahc)->platform_data->sim_b)
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
|
||||
#endif
|
||||
/************************* Forward Declarations *******************************/
|
||||
typedef device_t ahc_dev_softc_t;
|
||||
typedef union ccb *ahc_io_ctx_t;
|
||||
@ -144,10 +149,10 @@ typedef union ccb *ahc_io_ctx_t;
|
||||
* transfer is as fragmented as possible and unaligned, this turns out to
|
||||
* be the number of paged sized transfers in MAXPHYS plus an extra element
|
||||
* to handle any unaligned residual. The sequencer fetches SG elements
|
||||
* in 128 byte chucks, so make the number per-transaction a nice multiple
|
||||
* of 16 (8 byte S/G elements).
|
||||
* in cacheline sized chucks, so make the number per-transaction an even
|
||||
* multiple of 16 which should align us on even the largest of cacheline
|
||||
* boundaries.
|
||||
*/
|
||||
/* XXX Worth the space??? */
|
||||
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
|
||||
|
||||
/* This driver supports target mode */
|
||||
@ -505,5 +510,5 @@ ahc_platform_flushwork(struct ahc_softc *ahc)
|
||||
timeout_t ahc_timeout;
|
||||
void ahc_done(struct ahc_softc *ahc, struct scb *scb);
|
||||
void ahc_send_async(struct ahc_softc *, char /*channel*/,
|
||||
u_int /*target*/, u_int /*lun*/, ac_code);
|
||||
u_int /*target*/, u_int /*lun*/, ac_code, void *arg);
|
||||
#endif /* _AIC7XXX_FREEBSD_H_ */
|
||||
|
@ -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_inline.h#19 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -188,7 +188,7 @@ ahc_name(struct ahc_softc *ahc)
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
|
||||
static __inline int ahc_check_residual(struct scb *scb);
|
||||
static __inline void ahc_update_residual(struct scb *scb);
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc,
|
||||
char channel, u_int our_id,
|
||||
@ -211,15 +211,16 @@ static __inline uint32_t
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static __inline int
|
||||
ahc_check_residual(struct scb *scb)
|
||||
static __inline void
|
||||
ahc_update_residual(struct scb *scb)
|
||||
{
|
||||
struct status_pkt *sp;
|
||||
uint32_t sgptr;
|
||||
|
||||
sp = &scb->hscb->shared_data.status;
|
||||
if ((scb->hscb->sgptr & SG_RESID_VALID) != 0)
|
||||
return (1);
|
||||
return (0);
|
||||
sgptr = ahc_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_RESID_VALID) != 0)
|
||||
ahc_calc_residual(scb);
|
||||
else
|
||||
ahc_set_residual(scb, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -49,6 +49,7 @@ static int ahc_debug = AHC_DEBUG;
|
||||
#if UNUSED
|
||||
static void ahc_dump_targcmd(struct target_cmd *cmd);
|
||||
#endif
|
||||
static int ahc_modevent(module_t mod, int type, void *data);
|
||||
static void ahc_action(struct cam_sim *sim, union ccb *ccb);
|
||||
static void ahc_get_tran_settings(struct ahc_softc *ahc,
|
||||
int our_id, char channel,
|
||||
@ -572,9 +573,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
|
||||
update_type |= AHC_TRANS_GOAL;
|
||||
discenable = &tstate->discenable;
|
||||
tagenable = &tstate->tagenable;
|
||||
tinfo->current.protocol_version =
|
||||
tinfo->curr.protocol_version =
|
||||
cts->protocol_version;
|
||||
tinfo->current.transport_version =
|
||||
tinfo->curr.transport_version =
|
||||
cts->transport_version;
|
||||
tinfo->goal.protocol_version =
|
||||
cts->protocol_version;
|
||||
@ -777,7 +778,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
|
||||
&& tinfo->user.transport_version >= 3) {
|
||||
tinfo->goal.transport_version =
|
||||
tinfo->user.transport_version;
|
||||
tinfo->current.transport_version =
|
||||
tinfo->curr.transport_version =
|
||||
tinfo->user.transport_version;
|
||||
}
|
||||
|
||||
@ -932,7 +933,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
|
||||
devinfo.target, &tstate);
|
||||
|
||||
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
||||
tinfo = &targ_info->current;
|
||||
tinfo = &targ_info->curr;
|
||||
else
|
||||
tinfo = &targ_info->user;
|
||||
|
||||
@ -990,7 +991,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
|
||||
devinfo.target, &tstate);
|
||||
|
||||
if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
|
||||
tinfo = &targ_info->current;
|
||||
tinfo = &targ_info->curr;
|
||||
else
|
||||
tinfo = &targ_info->user;
|
||||
|
||||
@ -1206,7 +1207,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
|
||||
mask = SCB_GET_TARGET_MASK(ahc, scb);
|
||||
scb->hscb->scsirate = tinfo->scsirate;
|
||||
scb->hscb->scsioffset = tinfo->current.offset;
|
||||
scb->hscb->scsioffset = tinfo->curr.offset;
|
||||
if ((tstate->ultraenb & mask) != 0)
|
||||
scb->hscb->control |= ULTRAENB;
|
||||
|
||||
@ -1767,7 +1768,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
|
||||
void
|
||||
ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
u_int lun, ac_code code)
|
||||
u_int lun, ac_code code, void *opt_arg)
|
||||
{
|
||||
struct ccb_trans_settings cts;
|
||||
struct cam_path *path;
|
||||
@ -1782,8 +1783,12 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
|
||||
switch (code) {
|
||||
case AC_TRANSFER_NEG:
|
||||
{
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
struct ccb_trans_settings_scsi *scsi;
|
||||
|
||||
cts.type = CTS_TYPE_CURRENT_SETTINGS;
|
||||
scsi = &cts.proto_specific.scsi;
|
||||
#else
|
||||
cts.flags = CCB_TRANS_CURRENT_SETTINGS;
|
||||
#endif
|
||||
@ -1794,7 +1799,25 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
|
||||
: ahc->our_id_b,
|
||||
channel, &cts);
|
||||
arg = &cts;
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
scsi->valid &= ~CTS_SCSI_VALID_TQ;
|
||||
scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
|
||||
#else
|
||||
cts.valid &= ~CCB_TRANS_TQ_VALID;
|
||||
cts.flags &= ~CCB_TRANS_TAG_ENB;
|
||||
#endif
|
||||
if (opt_arg == NULL)
|
||||
break;
|
||||
if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED)
|
||||
#ifdef AHC_NEW_TRAN_SETTINGS
|
||||
scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
|
||||
scsi->valid |= CTS_SCSI_VALID_TQ;
|
||||
#else
|
||||
cts.flags |= CCB_TRANS_TAG_ENB;
|
||||
cts.valid |= CCB_TRANS_TQ_VALID;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case AC_SENT_BDR:
|
||||
case AC_BUS_RESET:
|
||||
break;
|
||||
@ -1906,3 +1929,20 @@ ahc_dump_targcmd(struct target_cmd *cmd)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ahc_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
/* XXX Deal with busy status on unload. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static moduledata_t ahc_mod = {
|
||||
"ahc",
|
||||
ahc_modevent,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
|
||||
MODULE_DEPEND(ahc, cam, 1, 1, 1);
|
||||
MODULE_VERSION(ahc, 1);
|
||||
|
@ -41,7 +41,9 @@
|
||||
#define AHC_NEW_TRAN_SETTINGS
|
||||
#endif /* CAM_NEW_TRAN_CODE */
|
||||
#include <opt_aic7xxx.h> /* for config options */
|
||||
#include <pci.h> /* for NPCI */
|
||||
#ifndef NPCI
|
||||
#include <pci.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -96,6 +98,9 @@
|
||||
(SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \
|
||||
: (ahc)->platform_data->sim_b)
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
|
||||
#endif
|
||||
/************************* Forward Declarations *******************************/
|
||||
typedef device_t ahc_dev_softc_t;
|
||||
typedef union ccb *ahc_io_ctx_t;
|
||||
@ -144,10 +149,10 @@ typedef union ccb *ahc_io_ctx_t;
|
||||
* transfer is as fragmented as possible and unaligned, this turns out to
|
||||
* be the number of paged sized transfers in MAXPHYS plus an extra element
|
||||
* to handle any unaligned residual. The sequencer fetches SG elements
|
||||
* in 128 byte chucks, so make the number per-transaction a nice multiple
|
||||
* of 16 (8 byte S/G elements).
|
||||
* in cacheline sized chucks, so make the number per-transaction an even
|
||||
* multiple of 16 which should align us on even the largest of cacheline
|
||||
* boundaries.
|
||||
*/
|
||||
/* XXX Worth the space??? */
|
||||
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
|
||||
|
||||
/* This driver supports target mode */
|
||||
@ -505,5 +510,5 @@ ahc_platform_flushwork(struct ahc_softc *ahc)
|
||||
timeout_t ahc_timeout;
|
||||
void ahc_done(struct ahc_softc *ahc, struct scb *scb);
|
||||
void ahc_send_async(struct ahc_softc *, char /*channel*/,
|
||||
u_int /*target*/, u_int /*lun*/, ac_code);
|
||||
u_int /*target*/, u_int /*lun*/, ac_code, void *arg);
|
||||
#endif /* _AIC7XXX_FREEBSD_H_ */
|
||||
|
@ -30,22 +30,14 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx_pci.c#21 $
|
||||
* $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */
|
||||
#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */
|
||||
@ -271,7 +263,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
|
||||
{
|
||||
ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK,
|
||||
ID_DEV_VENDOR_MASK,
|
||||
"Adaptec 2930C SCSI adapter (VAR)",
|
||||
"Adaptec 2930C Ultra SCSI adapter (VAR)",
|
||||
ahc_aic7860_setup
|
||||
},
|
||||
/* aic7870 based controllers */
|
||||
@ -460,7 +452,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
|
||||
{
|
||||
ID_AIC7892_ARO,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec aic7892 Ultra2 SCSI adapter (ARO)",
|
||||
"Adaptec aic7892 Ultra160 SCSI adapter (ARO)",
|
||||
ahc_aic7892_setup
|
||||
},
|
||||
/* aic7895 based controllers */
|
||||
@ -554,13 +546,13 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
|
||||
{
|
||||
ID_AIC7859 & ID_DEV_VENDOR_MASK,
|
||||
ID_DEV_VENDOR_MASK,
|
||||
"Adaptec aic7859 Ultra SCSI adapter",
|
||||
"Adaptec aic7859 SCSI adapter",
|
||||
ahc_aic7860_setup
|
||||
},
|
||||
{
|
||||
ID_AIC7860 & ID_DEV_VENDOR_MASK,
|
||||
ID_DEV_VENDOR_MASK,
|
||||
"Adaptec aic7860 SCSI adapter",
|
||||
"Adaptec aic7860 Ultra SCSI adapter",
|
||||
ahc_aic7860_setup
|
||||
},
|
||||
{
|
||||
@ -786,7 +778,8 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
/* Perform ALT-Mode Setup */
|
||||
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
|
||||
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
|
||||
ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS);
|
||||
ahc_outb(ahc, OPTIONMODE,
|
||||
OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS);
|
||||
ahc_outb(ahc, SFUNCT, sfunct);
|
||||
|
||||
/* Normal mode setup */
|
||||
@ -794,10 +787,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
|TARGCRCENDEN);
|
||||
}
|
||||
|
||||
error = ahc_pci_map_int(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
dscommand0 = ahc_inb(ahc, DSCOMMAND0);
|
||||
dscommand0 |= MPARCKEN|CACHETHEN;
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
@ -826,6 +815,19 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
/*bytes*/1) & CACHESIZE;
|
||||
ahc->pci_cachesize *= 4;
|
||||
|
||||
/*
|
||||
* We cannot perform ULTRA speeds without the presense
|
||||
* of the external precision resistor.
|
||||
*/
|
||||
if ((ahc->features & AHC_ULTRA) != 0) {
|
||||
uint32_t devconfig;
|
||||
|
||||
devconfig = ahc_pci_read_config(ahc->dev_softc,
|
||||
DEVCONFIG, /*bytes*/4);
|
||||
if ((devconfig & REXTVALID) == 0)
|
||||
ahc->features &= ~AHC_ULTRA;
|
||||
}
|
||||
|
||||
/* See if we have a SEEPROM and perform auto-term */
|
||||
check_extport(ahc, &sxfrctl1);
|
||||
|
||||
@ -880,20 +882,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
if ((sxfrctl1 & STPWEN) != 0)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
|
||||
/*
|
||||
* We cannot perform ULTRA speeds without
|
||||
* the presense of the external precision
|
||||
* resistor.
|
||||
*/
|
||||
if ((ahc->features & AHC_ULTRA) != 0) {
|
||||
uint32_t devconfig;
|
||||
|
||||
devconfig = ahc_pci_read_config(ahc->dev_softc,
|
||||
DEVCONFIG, /*bytes*/4);
|
||||
if ((devconfig & REXTVALID) == 0)
|
||||
ahc->flags |= AHC_ULTRA_DISABLED;
|
||||
}
|
||||
|
||||
/* Core initialization */
|
||||
error = ahc_init(ahc);
|
||||
if (error != 0)
|
||||
@ -907,6 +895,10 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
/*
|
||||
* Allow interrupts now that we are completely setup.
|
||||
*/
|
||||
error = ahc_pci_map_int(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahc_intr_enable(ahc, TRUE);
|
||||
|
||||
return (0);
|
||||
|
Loading…
Reference in New Issue
Block a user