ahc_eisa.c:

ahc_pci.c:
		Add detach support.

		Make use of soft allocated on our behalf by newbus.

		For PCI devices, disable the mapping type we aren't
		using for extra protection from rogue code.

	aic7xxx_93cx6.c:
	aic7xxx_93cx6.h:
		Sync perforce IDs.

	aic7xxx_freebsd.c:
		Capture the eventhandle returned by EVENTHANDER_REGISTER
		so we can kill the handler off during detach.

		Use AHC_* constants instead of hard coded numbers in a
		few more places.

		Test PPR option state when deciding to "really" negotiate
		when the CAM_NEGOTIATE flag is passed in a CCB.

		Make use of core "ahc_pause_and_flushwork" routine in our
		timeout handler rather than re-inventing this code.

		Cleanup all of our resources (really!) in ahc_platform_free().
		We should be all set to become a module now.

		Implement the core ahc_detach() routine shared by all of
		the FreeBSD front-ends.

	aic7xxx_freebsd.h:
		Softc storage for our event handler.

		Null implementation for the ahc_platform_flushwork() OSM
		callback.  FreeBSD doesn't need this as XPT callbacks are
		safe from all contexts and are done directly in ahc_done().

	aic7xxx_inline.h:
		Implement new lazy interrupt scheme.  To avoid an extra
		PCI bus read, we first check our completion queues to
		see if any work has completed.  If work is available, we
		assume that this is the source of the interrupt and skip
		reading INTSTAT.  Any remaining interrupt status will be
		cleared by a second call to the interrupt handler should
		the interrupt line still be asserted.  This drops the
		interrupt handler down to a single PCI bus read in the
		common case of I/O completion.  This is the same overhead
		as in the not so distant past, but the extra sanity of
		perforning a PCI read after clearing the command complete
		interrupt and before running the completion queue to avoid
		missing command complete interrupts added a cycle.

	aic7xxx.c:
		During initialization, be sure to initialize all scratch
		ram locations before they are read to avoid parity errors.
		In this case, we use a new function, ahc_unbusy_tcl() to
		initialize the scratch ram busy target table.

		Replace instances of ahc_index_busy_tcl() used to unbusy
		a tcl without looking at the old value with ahc_unbusy_tcl().

		Modify ahc_sent_msg so that it can find single byte messages.
		ahc_sent_msg is now used to determine if a transfer negotiation
		attempt resulted in a bus free.

		Be more careful in filtering out only the SCSI interrupts
		of interest in ahc_handle_scsiint.

		Rearrange interrupt clearing code to ensure that at least
		one PCI transaction occurrs after hitting CLRSINT1 and
		writting to CLRINT.  CLRSINT1 writes take a bit to
		take effect, and the re-arrangement provides sufficient
		delay to ensure the write to CLRINT is effective.  The
		old code might report a spurious interrupt on some "fast"
		chipsets.

		export ahc-update_target_msg_request for use by OSM code.

		If a target does not respond to our ATN request, clear
		it once we move to a non-message phase.  This avoids
		sending a MSG_NOOP in some later message out phase.

		Use max lun and max target constants instead of
		hard-coded values.

		Use softc storage built into our device_t under FreeBSD.

		Fix a bug in ahc_free() that caused us to delete
		resources that were not allocated.

		Clean up any tstate/lstate info in ahc_free().

		Clear the powerdown state in ahc_reset() so that
		registers can be accessed.

		Add a preliminary function for pausing the chip and
		processing any posted work.

		Add a preliminary suspend and resume functions.

	aic7xxx.h:
		Limit the number of supported luns to 64.  We don't
		support information unit transfers, so this is the
		maximum that makes sense for these chips.

		Add a new flag AHC_ALL_INTERRUPTS that forces the
		processing of all interrupt state in a single invokation
		of ahc_intr().  When the flag is not set, we use the
		lazy interrupt handling scheme.

		Add data structures to store controller state while
		we are suspended.

		Use constants instead of hard coded values where appropriate.

		Correct some harmless "unsigned/signed" conflicts.

	aic7xxx.seq:
		Only perform the SCSIBUSL fix on ULTRA2 or newer controllers.
		Older controllers seem to be confused by this.

		In target mode, ignore PHASEMIS during data phases.
		This bit seems to be flakey on U160 controllers acting
		in target mode.

	aic7xxx_pci.c:
		Add support for the 29160C CPCI adapter.

		Add definitions for subvendor ID information
		available for devices with the "9005" vendor id.
		We currently use this information to determine
		if a multi-function device doesn't have the second
		channel hooked up on a board.

		Add rudimentary power mode code so we can put the
		controller into the D0 state.  In the future this
		will be an OSM callback so that in FreeBSD we don't
		duplicate functionality provided by the PCI code.
		The powerstate code was added after I'd completed
		my regression tests on this code.

		Only capture "left over BIOS state" if the POWRDN
		setting is not set in HCNTRL.

		In target mode, don't bother sending incremental
		CRC data.
This commit is contained in:
Justin T. Gibbs 2000-12-20 01:11:37 +00:00
parent 64dee60f8c
commit 56a7c4a852
13 changed files with 713 additions and 225 deletions

View File

@ -194,14 +194,14 @@ static device_method_t ahc_eisa_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, aic7770_probe),
DEVMETHOD(device_attach, aic7770_attach),
DEVMETHOD(device_detach, ahc_detach),
{ 0, 0 }
};
static driver_t ahc_eisa_driver = {
"ahc",
ahc_eisa_methods,
1, /* unused */
sizeof(struct ahc_softc)
};
static devclass_t ahc_devclass;

View File

@ -45,6 +45,7 @@ static device_method_t ahc_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ahc_pci_probe),
DEVMETHOD(device_attach, ahc_pci_attach),
DEVMETHOD(device_detach, ahc_detach),
{ 0, 0 }
};
@ -57,6 +58,7 @@ static driver_t ahc_pci_driver = {
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);
static int
ahc_pci_probe(device_t dev)
@ -92,7 +94,7 @@ ahc_pci_attach(device_t dev)
if (name == NULL)
return (ENOMEM);
strcpy(name, device_get_nameunit(dev));
ahc = ahc_alloc(NULL, name);
ahc = ahc_alloc(dev, name);
if (ahc == NULL)
return (ENOMEM);
@ -139,6 +141,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
regs_id = 0;
#ifdef AHC_ALLOW_MEMIO
if ((command & PCIM_CMD_MEMEN) != 0) {
regs_type = SYS_RES_MEMORY;
regs_id = AHC_PCI_MEMADDR;
regs = bus_alloc_resource(ahc->dev_softc, regs_type,
@ -161,6 +164,11 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
bus_release_resource(ahc->dev_softc, regs_type,
regs_id, regs);
regs = NULL;
} else {
command &= ~PCIM_CMD_PORTEN;
ahc_pci_write_config(ahc->dev_softc,
PCIR_COMMAND,
command, /*bytes*/1);
}
}
}
@ -172,6 +180,10 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
&regs_id, 0, ~0, 1, RF_ACTIVE);
ahc->tag = rman_get_bustag(regs);
ahc->bsh = rman_get_bushandle(regs);
command &= ~PCIM_CMD_MEMEN;
ahc_pci_write_config(ahc->dev_softc,
PCIR_COMMAND,
command, /*bytes*/1);
}
ahc->platform_data->regs_res_type = regs_type;
ahc->platform_data->regs_res_id = regs_id;

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#18 $
* $Id: //depot/src/aic7xxx/aic7xxx.c#20 $
*
* $FreeBSD$
*/
@ -132,18 +132,16 @@ struct ahc_syncrate ahc_syncrates[] =
static struct tmode_tstate*
ahc_alloc_tstate(struct ahc_softc *ahc,
u_int scsi_id, char channel);
#ifdef AHC_TARGET_MODE
static void ahc_free_tstate(struct ahc_softc *ahc,
u_int scsi_id, char channel, int force);
#endif
static struct ahc_syncrate*
ahc_devlimited_syncrate(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *,
u_int *period,
u_int *ppr_options,
role_t role);
static void ahc_update_target_msg_request(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
struct ahc_initiator_tinfo *tinfo,
int force, int paused);
static void ahc_update_pending_syncrates(struct ahc_softc *ahc);
static void ahc_fetch_devinfo(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
@ -167,8 +165,13 @@ static void ahc_construct_ppr(struct ahc_softc *ahc,
u_int bus_width, u_int ppr_options);
static void ahc_clear_msg_state(struct ahc_softc *ahc);
static void ahc_handle_message_phase(struct ahc_softc *ahc);
static int ahc_sent_msg(struct ahc_softc *ahc,
u_int msgtype, int full);
typedef enum {
AHCMSG_1B,
AHCMSG_2B,
AHCMSG_EXT
} ahc_msgtype;
static int ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type,
u_int msgval, int full);
static int ahc_parse_msg(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
static int ahc_handle_msg_reject(struct ahc_softc *ahc,
@ -181,10 +184,9 @@ static void ahc_handle_devreset(struct ahc_softc *ahc,
int verbose_level);
static bus_dmamap_callback_t ahc_dmamap_cb;
static void ahc_build_free_scb_list(struct ahc_softc *ahc);
static int ahc_init_scbdata(struct ahc_softc *ahc);
static void ahc_fini_scbdata(struct ahc_softc *ahc);
static void ahc_busy_tcl(struct ahc_softc *ahc,
u_int tcl, u_int busyid);
static void ahc_qinfifo_requeue(struct ahc_softc *ahc,
struct scb *prev_scb,
struct scb *scb);
@ -501,6 +503,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
sc->control = 0;
/*
* XXX Still true???
* Would be nice to preserve DISCENB here,
* but due to the way we manage busy targets,
* we can't.
@ -566,8 +569,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
ahc_index_busy_tcl(ahc,
BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
ahc_inb(ahc, SAVED_LUN)),
/*unbusy*/FALSE), ahc_inb(ahc, SINDEX));
ahc_inb(ahc, SAVED_LUN))),
ahc_inb(ahc, SINDEX));
printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
"SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
@ -838,8 +841,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
ahc_index_busy_tcl(ahc,
BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
ahc_inb(ahc, SAVED_LUN)),
/*unbusy*/FALSE), ahc_inb(ahc, SINDEX),
ahc_inb(ahc, SAVED_LUN))),
ahc_inb(ahc, SINDEX),
ahc_inb(ahc, ACCUM));
printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
"SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
@ -888,7 +891,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
status0 = ahc_inb(ahc, SSTAT0) & IOERR;
else
status0 = 0;
status = ahc_inb(ahc, SSTAT1);
status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
if (status == 0 && status0 == 0) {
if ((ahc->features & AHC_TWIN) != 0) {
/* Try the other channel */
@ -1040,16 +1043,16 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, SCSISEQ,
ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
if (lastphase == P_MESGOUT) {
u_int message;
struct ahc_devinfo devinfo;
u_int tag;
message = ahc->msgout_buf[ahc->msgout_index - 1];
ahc_fetch_devinfo(ahc, &devinfo);
tag = SCB_LIST_NULL;
switch (message) {
case MSG_ABORT_TAG:
tag = scb->hscb->tag;
/* FALLTRHOUGH */
case MSG_ABORT:
if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
|| ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
if (ahc->msgout_buf[ahc->msgout_index - 1]
== MSG_ABORT_TAG)
tag = scb->hscb->tag;
ahc_print_path(ahc, scb);
printf("SCB %d - Abort %s Completed.\n",
scb->hscb->tag, tag == SCB_LIST_NULL ?
@ -1059,9 +1062,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ROLE_INITIATOR,
CAM_REQ_ABORTED);
printerror = 0;
break;
case MSG_BUS_DEV_RESET:
{
} else if (ahc_sent_msg(ahc, AHCMSG_1B,
MSG_BUS_DEV_RESET, TRUE)) {
struct ahc_devinfo devinfo;
#ifdef __FreeBSD__
/*
@ -1089,10 +1091,45 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
"Bus Device Reset",
/*verbose_level*/0);
printerror = 0;
break;
}
default:
break;
} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
MSG_EXT_PPR, FALSE)) {
struct ahc_initiator_tinfo *tinfo;
struct tmode_tstate *tstate;
/*
* PPR Rejected. Try non-ppr negotiation
* and retry command.
*/
tinfo = ahc_fetch_transinfo(ahc,
devinfo.channel,
devinfo.our_scsiid,
devinfo.target,
&tstate);
tinfo->current.transport_version = 2;
tinfo->goal.transport_version = 2;
tinfo->goal.ppr_options = 0;
ahc_qinfifo_requeue_tail(ahc, scb);
printerror = 0;
} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
MSG_EXT_WDTR, FALSE)
|| ahc_sent_msg(ahc, AHCMSG_EXT,
MSG_EXT_SDTR, FALSE)) {
/*
* Negotiation Rejected. Go-async and
* retry command.
*/
ahc_set_width(ahc, &devinfo,
MSG_EXT_WDTR_BUS_8_BIT,
AHC_TRANS_CUR|AHC_TRANS_GOAL,
/*paused*/TRUE);
ahc_set_syncrate(ahc, &devinfo,
/*syncrate*/NULL,
/*period*/0, /*offset*/0,
/*ppr_options*/0,
AHC_TRANS_CUR|AHC_TRANS_GOAL,
/*paused*/TRUE);
ahc_qinfifo_requeue_tail(ahc, scb);
printerror = 0;
}
}
if (printerror != 0) {
@ -1153,6 +1190,9 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
/* 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
@ -1163,16 +1203,11 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
*/
ahc_outb(ahc, CLRSINT0, CLRSELINGO);
/* Clear interrupt state */
ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
restart_sequencer(ahc);
} else {
ahc_print_path(ahc, scb);
printf("Unknown SCSIINT. Status = 0x%x\n", status);
ahc_outb(ahc, CLRSINT1, status);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
unpause_sequencer(ahc);
panic("%s: Missing case in ahc_handle_scsiint. status = %x\n",
ahc_name(ahc), status);
}
}
@ -1253,10 +1288,10 @@ void
ahc_clear_intstat(struct ahc_softc *ahc)
{
/* Clear any interrupt conditions this may have caused */
ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
|CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG|
CLRREQINIT);
ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
}
@ -1591,7 +1626,7 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
* means the next time we send the initial identify messages for
* a new transaction.
*/
static void
void
ahc_update_target_msg_request(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
struct ahc_initiator_tinfo *tinfo,
@ -2028,6 +2063,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_index = 0;
ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
}
/*
* Build an appropriate transfer negotiation message for the
* currently active target.
@ -2181,6 +2217,13 @@ ahc_clear_msg_state(struct ahc_softc *ahc)
ahc->msgout_len = 0;
ahc->msgin_index = 0;
ahc->msg_type = MSG_TYPE_NONE;
if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) {
/*
* The target didn't care to respond to our
* message request, so clear ATN.
*/
ahc_outb(ahc, CLRSINT1, CLRATNO);
}
ahc_outb(ahc, MSG_OUT, MSG_NOOP);
}
@ -2441,7 +2484,7 @@ reswitch:
* least the first byte of the message.
*/
static int
ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full)
ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full)
{
int found;
u_int index;
@ -2451,20 +2494,19 @@ ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full)
while (index < ahc->msgout_len) {
if (ahc->msgout_buf[index] == MSG_EXTENDED) {
u_int end_index;
/* Found a candidate */
if (ahc->msgout_buf[index+2] == msgtype) {
u_int end_index;
end_index = index + 1 + ahc->msgout_buf[index + 1];
if (ahc->msgout_buf[index+2] == msgval
&& type == AHCMSG_EXT) {
end_index = index + 1
+ ahc->msgout_buf[index + 1];
if (full) {
if (ahc->msgout_index > end_index)
found = TRUE;
} else if (ahc->msgout_index > index)
found = TRUE;
}
break;
index = end_index;
} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
&& ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
@ -2472,8 +2514,15 @@ ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full)
index += 2;
} else {
/* Single byte message */
if (type == AHCMSG_1B
&& ahc->msgout_buf[index] == msgval
&& ahc->msgout_index > index)
found = TRUE;
index++;
}
if (found)
break;
}
return (found);
}
@ -2574,7 +2623,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* and didn't have to fall down to async
* transfers.
*/
if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/TRUE)) {
if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) {
/* We started it */
if (saved_offset != offset) {
/* Went too low - force async */
@ -2634,7 +2683,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
saved_width, bus_width);
}
if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/TRUE)) {
if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) {
/*
* Don't send a WDTR back to the
* target, since we asked first.
@ -2748,7 +2797,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
&offset, bus_width,
devinfo->role);
if (ahc_sent_msg(ahc, MSG_EXT_PPR, /*full*/TRUE)) {
if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) {
/*
* If we are unable to do any of the
* requested options (we went too low),
@ -2902,7 +2951,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
/* Might be necessary */
last_msg = ahc_inb(ahc, LAST_MSG);
if (ahc_sent_msg(ahc, MSG_EXT_PPR, /*full*/FALSE)) {
if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) {
/*
* Target does not support the PPR message.
* Attempt to negotiate SPI-2 style.
@ -2921,7 +2970,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc_build_transfer_msg(ahc, devinfo);
ahc->msgout_index = 0;
response = 1;
} else if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) {
} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
/* note 8bit xfers */
printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using "
@ -2946,7 +2995,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc->msgout_index = 0;
response = 1;
}
} else if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/FALSE)) {
} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) {
/* note asynch xfers and clear flag */
ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0,
/*offset*/0, /*ppr_options*/0,
@ -3150,7 +3199,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
*/
tstate = ahc->enabled_targets[devinfo->our_scsiid];
if (tstate != NULL) {
for (lun = 0; lun <= 7; lun++) {
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
struct tmode_lstate* lstate;
lstate = tstate->enabled_luns[lun];
@ -3214,12 +3263,16 @@ ahc_alloc(void *platform_arg, char *name)
struct ahc_softc *ahc;
int i;
#ifndef __FreeBSD__
ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
if (!ahc) {
printf("aic7xxx: cannot malloc softc!\n");
free(name, M_DEVBUF);
return NULL;
}
#else
ahc = device_get_softc((device_t)platform_arg);
#endif
memset(ahc, 0, sizeof(*ahc));
LIST_INIT(&ahc->pending_scbs);
/* We don't know or unit number until the OSM sets it */
@ -3325,22 +3378,27 @@ ahc_set_name(struct ahc_softc *ahc, char *name)
void
ahc_free(struct ahc_softc *ahc)
{
int i;
ahc_fini_scbdata(ahc);
switch (ahc->init_level) {
case 4:
default:
case 5:
ahc_shutdown(ahc);
TAILQ_REMOVE(&ahc_tailq, ahc, links);
/* FALLTHROUGH */
case 3:
case 4:
ahc_dmamap_unload(ahc, ahc->shared_data_dmat,
ahc->shared_data_dmamap);
/* FALLTHROUGH */
case 2:
case 3:
ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo,
ahc->shared_data_dmamap);
ahc_dmamap_destroy(ahc, ahc->shared_data_dmat,
ahc->shared_data_dmamap);
/* FALLTHROUGH */
case 2:
ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
case 1:
#ifndef __linux__
ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
@ -3349,15 +3407,38 @@ ahc_free(struct ahc_softc *ahc)
}
ahc_platform_free(ahc);
#if XXX
for () {
ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id,
char channel, int force);
for (i = 0; i < AHC_NUM_TARGETS; i++) {
struct tmode_tstate *tstate;
tstate = ahc->enabled_targets[i];
if (tstate != NULL) {
#if AHC_TARGET_MODE
int j;
for (j = 0; j < AHC_NUM_LUNS; j++) {
struct tmode_lstate *lstate;
lstate = tstate->enabled_luns[j];
if (lstate != NULL) {
xpt_free_path(lstate->path);
free(lstate, M_DEVBUF);
}
}
#endif
free(tstate, M_DEVBUF);
}
}
#if AHC_TARGET_MODE
if (ahc->black_hole != NULL) {
xpt_free_path(ahc->black_hole->path);
free(ahc->black_hole, M_DEVBUF);
}
#endif
if (ahc->name != NULL)
free(ahc->name, M_DEVBUF);
#ifndef __FreeBSD__
free(ahc, M_DEVBUF);
#endif
return;
}
@ -3424,8 +3505,8 @@ ahc_reset(struct ahc_softc *ahc)
if (wait == 0) {
printf("%s: WARNING - Failed chip reset! "
"Trying to initialize anyway.\n", ahc_name(ahc));
ahc_outb(ahc, HCNTRL, ahc->pause);
}
ahc_outb(ahc, HCNTRL, ahc->pause);
/* Determine channel configuration */
sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);
@ -3483,6 +3564,7 @@ ahc_probe_scbs(struct ahc_softc *ahc) {
int i;
for (i = 0; i < AHC_SCB_MAX; i++) {
ahc_outb(ahc, SCBPTR, i);
ahc_outb(ahc, SCB_BASE, i);
if (ahc_inb(ahc, SCB_BASE) != i)
@ -3515,33 +3597,11 @@ ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
*baddr = segs->ds_addr;
}
static int
ahc_init_scbdata(struct ahc_softc *ahc)
static void
ahc_build_free_scb_list(struct ahc_softc *ahc)
{
struct scb_data *scb_data;
int i;
scb_data = ahc->scb_data;
SLIST_INIT(&scb_data->free_scbs);
SLIST_INIT(&scb_data->sg_maps);
/* Allocate SCB resources */
scb_data->scbarray =
(struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
M_DEVBUF, M_NOWAIT);
if (scb_data->scbarray == NULL)
return (ENOMEM);
memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX);
/* Determine the number of hardware SCBs and initialize them */
scb_data->maxhscbs = ahc_probe_scbs(ahc);
if ((ahc->flags & AHC_PAGESCBS) != 0) {
/* SCB 0 heads the free list */
ahc_outb(ahc, FREE_SCBH, 0);
} else {
ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
}
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
ahc_outb(ahc, SCBPTR, i);
@ -3565,11 +3625,41 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* Ensure we clear the 0 SCB's control byte. */
ahc_outb(ahc, SCBPTR, 0);
ahc_outb(ahc, SCB_CONTROL, 0);
}
scb_data->maxhscbs = i;
static int
ahc_init_scbdata(struct ahc_softc *ahc)
{
struct scb_data *scb_data;
if (ahc->scb_data->maxhscbs == 0)
panic("%s: No SCB space found", ahc_name(ahc));
scb_data = ahc->scb_data;
SLIST_INIT(&scb_data->free_scbs);
SLIST_INIT(&scb_data->sg_maps);
/* Allocate SCB resources */
scb_data->scbarray =
(struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
M_DEVBUF, M_NOWAIT);
if (scb_data->scbarray == NULL)
return (ENOMEM);
memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX);
/* Determine the number of hardware SCBs and initialize them */
scb_data->maxhscbs = ahc_probe_scbs(ahc);
if ((ahc->flags & AHC_PAGESCBS) != 0) {
/* SCB 0 heads the free list */
ahc_outb(ahc, FREE_SCBH, 0);
} else {
ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
}
if (ahc->scb_data->maxhscbs == 0) {
printf("%s: No SCB space found\n", ahc_name(ahc));
return (ENXIO);
}
ahc_build_free_scb_list(ahc);
/*
* Create our DMA tags. These tags define the kinds of device
@ -3730,6 +3820,8 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
case 1:
ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
break;
case 0:
break;
}
if (scb_data->scbarray != NULL)
free(scb_data->scbarray, M_DEVBUF);
@ -4189,7 +4281,7 @@ ahc_init(struct ahc_softc *ahc)
/* There are no untagged SCBs active yet. */
for (i = 0; i < 16; i++) {
ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0), /*unbusy*/TRUE);
ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
if ((ahc->features & AHC_SCB_BTT) != 0) {
int lun;
@ -4197,11 +4289,8 @@ ahc_init(struct ahc_softc *ahc)
* The SCB based BTT allows an entry per
* target and lun pair.
*/
for (lun = 1; lun < AHC_NUM_LUNS; lun++) {
ahc_index_busy_tcl(ahc,
BUILD_TCL(i << 4, lun),
/*unbusy*/TRUE);
}
for (lun = 1; lun < AHC_NUM_LUNS; lun++)
ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
}
}
@ -4316,13 +4405,175 @@ ahc_init(struct ahc_softc *ahc)
return (0);
}
/*
* Ensure that the card is paused in a location
* outside of all critical sections and that all
* pending work is completed prior to returning.
* This routine should only be called from outside
* an interrupt context.
*/
void
ahc_pause_and_flushwork(struct ahc_softc *ahc)
{
ahc->flags |= AHC_ALL_INTERRUPTS;
do {
ahc_intr(ahc);
pause_sequencer(ahc);
ahc_clear_critical_section(ahc);
} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
ahc_platform_flushwork(ahc);
ahc->flags &= ~AHC_ALL_INTERRUPTS;
}
int
ahc_suspend(struct ahc_softc *ahc)
{
uint8_t *ptr;
int i;
ahc_pause_and_flushwork(ahc);
if (LIST_FIRST(&ahc->pending_scbs) != NULL)
return (EBUSY);
#if AHC_TARGET_MODE
/*
* XXX What about ATIOs that have not yet been serviced?
* Perhaps we should just refuse to be suspended if we
* are acting in a target role.
*/
if (ahc->pending_device != NULL)
return (EBUSY);
#endif
/* Save volatile registers */
ahc->suspend_state.scsiseq = ahc_inb(ahc, SCSISEQ);
ahc->suspend_state.sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
ahc->suspend_state.sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
ahc->suspend_state.simode0 = ahc_inb(ahc, SIMODE0);
ahc->suspend_state.simode1 = ahc_inb(ahc, SIMODE1);
ahc->suspend_state.seltimer = ahc_inb(ahc, SELTIMER);
ahc->suspend_state.seqctl = ahc_inb(ahc, SEQCTL);
if ((ahc->chip & AHC_PCI) != 0) {
ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
}
if ((ahc->features & AHC_DT) != 0) {
u_int sfunct;
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE);
ahc_outb(ahc, SFUNCT, sfunct);
ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1);
}
if ((ahc->features & AHC_MULTI_FUNC) != 0)
ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR);
if ((ahc->features & AHC_ULTRA2) != 0)
ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
ptr = ahc->suspend_state.scratch_ram;
for (i = 0; i < 64; i++)
*ptr++ = ahc_inb(ahc, SRAM_BASE + i);
if ((ahc->features & AHC_MORE_SRAM) != 0) {
for (i = 0; i < 16; i++)
*ptr++ = ahc_inb(ahc, TARG_OFFSET + i);
}
ptr = ahc->suspend_state.btt;
if ((ahc->flags & AHC_SCB_BTT) != 0) {
for (i = 0;i < AHC_NUM_TARGETS; i++) {
int j;
for (j = 0;j < AHC_NUM_LUNS; j++) {
u_int tcl;
tcl = BUILD_TCL(i << 4, j);
*ptr = ahc_index_busy_tcl(ahc, tcl);
}
}
}
ahc_shutdown(ahc);
return (0);
}
int
ahc_resume(struct ahc_softc *ahc)
{
uint8_t *ptr;
int i;
ahc_reset(ahc);
ahc_build_free_scb_list(ahc);
/* Restore volatile registers */
ahc_outb(ahc, SCSISEQ, ahc->suspend_state.scsiseq);
ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.sxfrctl0);
ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.sxfrctl1);
ahc_outb(ahc, SIMODE0, ahc->suspend_state.simode0);
ahc_outb(ahc, SIMODE1, ahc->suspend_state.simode1);
ahc_outb(ahc, SELTIMER, ahc->suspend_state.seltimer);
ahc_outb(ahc, SEQCTL, ahc->suspend_state.seqctl);
if ((ahc->chip & AHC_PCI) != 0) {
ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0);
ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus);
}
if ((ahc->features & AHC_DT) != 0) {
u_int sfunct;
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode);
ahc_outb(ahc, SFUNCT, sfunct);
ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1);
}
if ((ahc->features & AHC_MULTI_FUNC) != 0)
ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr);
if ((ahc->features & AHC_ULTRA2) != 0)
ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh);
ptr = ahc->suspend_state.scratch_ram;
for (i = 0; i < 64; i++)
ahc_outb(ahc, SRAM_BASE + i, *ptr++);
if ((ahc->features & AHC_MORE_SRAM) != 0) {
for (i = 0; i < 16; i++)
ahc_outb(ahc, TARG_OFFSET + i, *ptr++);
}
ptr = ahc->suspend_state.btt;
if ((ahc->flags & AHC_SCB_BTT) != 0) {
for (i = 0;i < AHC_NUM_TARGETS; i++) {
int j;
for (j = 0;j < AHC_NUM_LUNS; j++) {
u_int tcl;
tcl = BUILD_TCL(i << 4, j);
ahc_busy_tcl(ahc, tcl, *ptr);
}
}
}
return (0);
}
/************************** Busy Target Table *********************************/
/*
* Return the untagged transaction id for a given target/channel lun.
* Optionally, clear the entry.
*/
u_int
ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl, int unbusy)
ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
{
u_int scbid;
u_int target_offset;
@ -4333,21 +4584,33 @@ ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl, int unbusy)
saved_scbptr = ahc_inb(ahc, SCBPTR);
ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl));
if (unbusy)
ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl),
SCB_LIST_NULL);
ahc_outb(ahc, SCBPTR, saved_scbptr);
} else {
target_offset = TCL_TARGET_OFFSET(tcl);
scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset);
if (unbusy)
ahc_outb(ahc, BUSY_TARGETS + target_offset,
SCB_LIST_NULL);
}
return (scbid);
}
void
ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
{
u_int target_offset;
if ((ahc->features & AHC_SCB_BTT) != 0) {
u_int saved_scbptr;
saved_scbptr = ahc_inb(ahc, SCBPTR);
ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL);
ahc_outb(ahc, SCBPTR, saved_scbptr);
} else {
target_offset = TCL_TARGET_OFFSET(tcl);
ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL);
}
}
void
ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid)
{
@ -4939,8 +5202,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
for (;i < maxtarget; i++) {
for (j = minlun;j < maxlun; j++)
ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, j),
/*unbusy*/TRUE);
ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j));
}
/*
@ -5107,7 +5369,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
tstate = ahc->enabled_targets[target];
if (tstate == NULL)
continue;
for (lun = 0; lun <= 7; lun++) {
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
struct tmode_lstate* lstate;
lstate = tstate->enabled_luns[lun];
@ -5762,7 +6024,7 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb,
if (ccb->ccb_h.target_id > max_id)
return (CAM_TID_INVALID);
if (ccb->ccb_h.target_lun > 7)
if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS)
return (CAM_LUN_INVALID);
*tstate = ahc->enabled_targets[ccb->ccb_h.target_id];

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#13 $
* $Id: //depot/src/aic7xxx/aic7xxx.h#14 $
*
* $FreeBSD$
*/
@ -108,12 +108,11 @@ struct scb_platform_data;
/*
* The maximum number of supported luns.
* Although the identify message only supports 64 luns in SPI3, you
* can have 2^64 luns when information unit transfers are enabled.
* The max we can do sanely given the 8bit nature of the RISC engine
* on these chips is 256.
* The identify message only supports 64 luns in SPI3.
* You can have 2^64 luns when information unit transfers are enabled,
* but it is doubtful this driver will ever support IUTs.
*/
#define AHC_NUM_LUNS 256
#define AHC_NUM_LUNS 64
/*
* The maximum transfer per S/G segment.
@ -311,7 +310,8 @@ typedef enum {
* stored in SCB space rather
* than SRAM.
*/
AHC_BIOS_ENABLED = 0x80000
AHC_BIOS_ENABLED = 0x80000,
AHC_ALL_INTERRUPTS = 0x100000
} ahc_flag;
/*
@ -648,8 +648,8 @@ struct ahc_initiator_tinfo {
* negotiation is the same regardless of role.
*/
struct tmode_tstate {
struct tmode_lstate* enabled_luns[64]; /* NULL == disabled */
struct ahc_initiator_tinfo transinfo[16];
struct tmode_lstate* enabled_luns[AHC_NUM_LUNS];
struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS];
/*
* Per initiator state bitmasks.
@ -809,6 +809,27 @@ typedef enum {
/*********************** Software Configuration Structure *********************/
TAILQ_HEAD(scb_tailq, scb);
struct ahc_suspend_state {
uint8_t scsiseq;
uint8_t sxfrctl0;
uint8_t sxfrctl1;
/* scsiid */
uint8_t optionmode;
uint8_t simode0;
uint8_t simode1;
uint8_t seltimer;
uint8_t seqctl;
uint8_t dscommand0;
uint8_t dspcistatus;
/* hsmailbox */
uint8_t crccontrol1;
uint8_t scbbaddr;
/* Host and sequencer SCB counts */
uint8_t dff_thrsh;
uint8_t *scratch_ram;
uint8_t *btt;
};
struct ahc_softc {
bus_space_tag_t tag;
bus_space_handle_t bsh;
@ -839,7 +860,7 @@ struct ahc_softc {
* target. The driver only allows a single untagged
* transaction per target.
*/
struct scb_tailq untagged_queues[16];
struct scb_tailq untagged_queues[AHC_NUM_TARGETS];
/*
* Platform specific data.
@ -857,7 +878,7 @@ struct ahc_softc {
* As an initiator, we keep one target entry for our initiator
* ID to store our sync/wide transfer settings.
*/
struct tmode_tstate* enabled_targets[16];
struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS];
/*
* The black hole device responsible for handling requests for
@ -945,6 +966,9 @@ struct ahc_softc {
*/
bus_addr_t dma_bug_buf;
/* Information saved through suspend/resume cycles */
struct ahc_suspend_state suspend_state;
/* Number of enabled target mode device on this card */
u_int enabled_luns;
@ -997,7 +1021,7 @@ struct ahc_pci_identity {
ahc_device_setup_t *setup;
};
extern struct ahc_pci_identity ahc_pci_ident_table [];
extern const int ahc_num_pci_devs;
extern const u_int ahc_num_pci_devs;
/***************************** VL/EISA Declarations ***************************/
struct aic7770_identity {
@ -1014,6 +1038,10 @@ extern const int ahc_num_aic7770_devs;
/*************************** Function Declarations ****************************/
/******************************************************************************/
u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
void ahc_busy_tcl(struct ahc_softc *ahc,
u_int tcl, u_int busyid);
/***************************** PCI Front End *********************************/
struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
@ -1043,6 +1071,9 @@ int ahc_softc_init(struct ahc_softc *,
struct ahc_probe_config*);
void ahc_controller_info(struct ahc_softc *ahc, char *buf);
int ahc_init(struct ahc_softc *ahc);
void ahc_pause_and_flushwork(struct ahc_softc *ahc);
int ahc_suspend(struct ahc_softc *ahc);
int ahc_resume(struct ahc_softc *ahc);
void ahc_softc_insert(struct ahc_softc *);
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
@ -1101,6 +1132,10 @@ void ahc_validate_width(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *tinfo,
u_int *bus_width,
role_t role);
void ahc_update_target_msg_request(struct ahc_softc *ahc,
struct ahc_devinfo *dinfo,
struct ahc_initiator_tinfo *tinfo,
int force, int paused);
void ahc_set_width(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
u_int width, u_int type, int paused);

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#14 $
* $Id: //depot/src/aic7xxx/aic7xxx.seq#15 $
*
* $FreeBSD$
*/
@ -884,7 +884,16 @@ ultra2_dma_loop:
* completes or the target changes phase.
*/
test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
test SSTAT1,PHASEMIS jz ultra2_dma_loop;
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;
}
ultra2_dmafinish:
test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;

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_93cx6.c#4 $
* $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#5 $
*
* $FreeBSD$
*/

View File

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

View File

@ -36,8 +36,6 @@
#include <dev/aic7xxx/aic7xxx_freebsd.h>
#include <dev/aic7xxx/aic7xxx_inline.h>
#include <sys/eventhandler.h>
#ifndef AHC_TMODE_ENABLE
#define AHC_TMODE_ENABLE 0
#endif
@ -48,8 +46,6 @@
static int ahc_debug = AHC_DEBUG;
#endif
static void ahc_freebsd_intr(void *arg);
#if UNUSED
static void ahc_dump_targcmd(struct target_cmd *cmd);
#endif
@ -115,7 +111,7 @@ ahc_attach(struct ahc_softc *ahc)
ahc_lock(ahc, &s);
/* Hook up our interrupt handler */
if ((error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
INTR_TYPE_CAM, ahc_freebsd_intr, ahc,
INTR_TYPE_CAM, ahc_platform_intr, ahc,
&ahc->platform_data->ih)) != 0) {
device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n",
error);
@ -231,8 +227,9 @@ fail:
if (count != 0)
/* We have to wait until after any system dumps... */
EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
ahc, SHUTDOWN_PRI_DEFAULT);
ahc->platform_data->eh =
EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
ahc, SHUTDOWN_PRI_DEFAULT);
return (count);
}
@ -241,7 +238,7 @@ fail:
* Catch an interrupt from the adapter
*/
void
ahc_freebsd_intr(void *arg)
ahc_platform_intr(void *arg)
{
struct ahc_softc *ahc;
@ -840,7 +837,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
cpi->hba_misc = 0;
cpi->hba_eng_cnt = 0;
cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7;
cpi->max_lun = 64;
cpi->max_lun = AHC_NUM_LUNS - 1;
if (SIM_IS_SCSIBUS_B(ahc, sim)) {
cpi->initiator_id = ahc->our_id_b;
if ((ahc->flags & AHC_RESET_BUS_B) == 0)
@ -1185,7 +1182,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
scb->hscb->control |= DISCENB;
if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
&& (tinfo->current.width != 0 || tinfo->current.period != 0)) {
&& (tinfo->goal.width != 0
|| tinfo->goal.period != 0
|| tinfo->goal.ppr_options != 0)) {
scb->flags |= SCB_NEGOTIATE;
scb->hscb->control |= MK_MESSAGE;
}
@ -1401,19 +1400,7 @@ ahc_timeout(void *arg)
ahc_lock(ahc, &s);
/*
* Ensure that the card doesn't do anything
* behind our back. Also make sure that we
* didn't "just" miss an interrupt that would
* affect this timeout.
*/
do {
ahc_freebsd_intr(ahc);
pause_sequencer(ahc);
} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
/* Make sure the sequencer is in a safe location. */
ahc_clear_critical_section(ahc);
ahc_pause_and_flushwork(ahc);
if ((scb->flags & SCB_ACTIVE) == 0) {
/* Previous timeout took care of me already */
@ -1812,18 +1799,36 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
void
ahc_platform_free(struct ahc_softc *ahc)
{
if (ahc->platform_data != NULL) {
if (ahc->platform_data->regs != NULL)
bus_release_resource(ahc->dev_softc,
ahc->platform_data->regs_res_type,
ahc->platform_data->regs_res_id,
ahc->platform_data->regs);
struct ahc_platform_data *pdata;
if (ahc->platform_data->irq != NULL)
pdata = ahc->platform_data;
if (pdata != NULL) {
device_printf(ahc->dev_softc, "Platform free\n");
if (pdata->regs != NULL)
bus_release_resource(ahc->dev_softc,
ahc->platform_data->irq_res_type,
0, ahc->platform_data->irq);
pdata->regs_res_type,
pdata->regs_res_id,
pdata->regs);
if (pdata->irq != NULL)
bus_release_resource(ahc->dev_softc,
pdata->irq_res_type,
0, pdata->irq);
if (pdata->sim_b != NULL) {
xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL);
xpt_free_path(pdata->path_b);
xpt_bus_deregister(cam_sim_path(pdata->sim_b));
cam_sim_free(pdata->sim_b, /*free_devq*/TRUE);
}
if (pdata->sim != NULL) {
xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
xpt_free_path(pdata->path);
xpt_bus_deregister(cam_sim_path(pdata->sim));
cam_sim_free(pdata->sim, /*free_devq*/TRUE);
}
if (pdata->eh != NULL)
EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
free(ahc->platform_data, M_DEVBUF);
}
}
@ -1835,6 +1840,21 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
return (0);
}
int
ahc_detach(device_t dev)
{
struct ahc_softc *ahc;
u_long s;
device_printf(dev, "detaching device\n");
ahc = device_get_softc(dev);
ahc_lock(ahc, &s);
bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih);
ahc_unlock(ahc, &s);
ahc_free(ahc);
return (0);
}
#if UNUSED
static void
ahc_dump_targcmd(struct target_cmd *cmd)

View File

@ -43,6 +43,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h> /* For device_t */
#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
@ -165,6 +166,7 @@ struct ahc_platform_data {
struct resource *regs;
struct resource *irq;
void *ih;
eventhandler_tag eh;
};
struct scb_platform_data {
@ -451,11 +453,20 @@ void ahc_notify_xfer_settings_change(struct ahc_softc *,
void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
int /*enable*/);
/***************************** Initialization *********************************/
/************************* Initialization/Teardown ****************************/
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
void ahc_platform_free(struct ahc_softc *ahc);
int ahc_attach(struct ahc_softc *);
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
int ahc_detach(device_t);
/****************************** Interrupts ************************************/
void ahc_platform_intr(void *);
static __inline void ahc_platform_flushwork(struct ahc_softc *ahc);
static __inline void
ahc_platform_flushwork(struct ahc_softc *ahc)
{
}
/************************ Misc Function Declarations **************************/
timeout_t ahc_timeout;

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_inline.h#10 $
* $Id: //depot/src/aic7xxx/aic7xxx_inline.h#12 $
*
* $FreeBSD$
*/
@ -107,8 +107,6 @@ unpause_sequencer(struct ahc_softc *ahc)
}
/*********************** Untagged Transaction Routines ************************/
u_int ahc_index_busy_tcl(struct ahc_softc *ahc,
u_int tcl, int unbusy);
static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
@ -349,8 +347,31 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
}
/************************** Interrupt Processing ******************************/
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
static __inline void ahc_intr(struct ahc_softc *ahc);
/*
* See if the firmware has posted any completed commands
* into our in-core command complete fifos.
*/
#define AHC_RUN_QOUTFIFO 0x1
#define AHC_RUN_TQINFIFO 0x2
static __inline u_int
ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
{
u_int retval;
retval = 0;
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
retval |= AHC_RUN_QOUTFIFO;
#ifdef AHC_TARGET_MODE
if ((ahc->flags & AHC_TARGETROLE) != 0
&& ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
retval |= AHC_RUN_TQINFIFO;
#endif
return (retval);
}
/*
* Catch an interrupt from the adapter
*/
@ -358,33 +379,43 @@ static __inline void
ahc_intr(struct ahc_softc *ahc)
{
u_int intstat;
intstat = ahc_inb(ahc, INTSTAT);
u_int queuestat;
/*
* Any interrupts to process?
* Instead of directly reading the interrupt status register,
* infer the cause of the interrupt by checking our in-core
* completion queues. This avoids a costly PCI bus read in
* most cases.
*/
intstat = 0;
if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
intstat = CMDCMPLT;
if ((intstat & INT_PEND) == 0
|| (ahc->flags & AHC_ALL_INTERRUPTS) != 0) {
intstat = ahc_inb(ahc, INTSTAT);
#if AHC_PCI_CONFIG > 0
if ((intstat & INT_PEND) == 0) {
if ((ahc->chip & AHC_PCI) != 0
&& (ahc->unsolicited_ints > 500)) {
if ((ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
ahc_pci_intr(ahc);
ahc->unsolicited_ints = 0;
} else {
ahc->unsolicited_ints++;
}
return;
} else {
ahc->unsolicited_ints = 0;
}
#else
if ((intstat & INT_PEND) == 0)
return;
if (ahc->unsolicited_ints > 500
&& (ahc->chip & AHC_PCI) != 0
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
ahc_pci_intr(ahc);
#endif
}
if (intstat == 0xFF)
/* Hot eject */
return;
if ((intstat & INT_PEND) == 0) {
ahc->unsolicited_ints++;
return;
}
ahc->unsolicited_ints = 0;
if (intstat & CMDCMPLT) {
ahc_outb(ahc, CLRINT, CLRCMDINT);
/*
* Ensure that the chip sees that we've cleared
* this interrupt before we walk the output fifo.
@ -394,9 +425,12 @@ ahc_intr(struct ahc_softc *ahc)
* and asserted the interrupt again.
*/
ahc_flush_device_writes(ahc);
ahc_run_qoutfifo(ahc);
#ifdef AHC_TARGET_MODE
if ((ahc->flags & AHC_TARGETROLE) != 0)
if ((queuestat & AHC_RUN_QOUTFIFO) != 0)
#endif
ahc_run_qoutfifo(ahc);
#ifdef AHC_TARGET_MODE
if ((queuestat & AHC_RUN_TQINFIFO) != 0)
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
#endif
}

View File

@ -36,8 +36,6 @@
#include <dev/aic7xxx/aic7xxx_freebsd.h>
#include <dev/aic7xxx/aic7xxx_inline.h>
#include <sys/eventhandler.h>
#ifndef AHC_TMODE_ENABLE
#define AHC_TMODE_ENABLE 0
#endif
@ -48,8 +46,6 @@
static int ahc_debug = AHC_DEBUG;
#endif
static void ahc_freebsd_intr(void *arg);
#if UNUSED
static void ahc_dump_targcmd(struct target_cmd *cmd);
#endif
@ -115,7 +111,7 @@ ahc_attach(struct ahc_softc *ahc)
ahc_lock(ahc, &s);
/* Hook up our interrupt handler */
if ((error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
INTR_TYPE_CAM, ahc_freebsd_intr, ahc,
INTR_TYPE_CAM, ahc_platform_intr, ahc,
&ahc->platform_data->ih)) != 0) {
device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n",
error);
@ -231,8 +227,9 @@ fail:
if (count != 0)
/* We have to wait until after any system dumps... */
EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
ahc, SHUTDOWN_PRI_DEFAULT);
ahc->platform_data->eh =
EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
ahc, SHUTDOWN_PRI_DEFAULT);
return (count);
}
@ -241,7 +238,7 @@ fail:
* Catch an interrupt from the adapter
*/
void
ahc_freebsd_intr(void *arg)
ahc_platform_intr(void *arg)
{
struct ahc_softc *ahc;
@ -840,7 +837,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
cpi->hba_misc = 0;
cpi->hba_eng_cnt = 0;
cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7;
cpi->max_lun = 64;
cpi->max_lun = AHC_NUM_LUNS - 1;
if (SIM_IS_SCSIBUS_B(ahc, sim)) {
cpi->initiator_id = ahc->our_id_b;
if ((ahc->flags & AHC_RESET_BUS_B) == 0)
@ -1185,7 +1182,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
scb->hscb->control |= DISCENB;
if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
&& (tinfo->current.width != 0 || tinfo->current.period != 0)) {
&& (tinfo->goal.width != 0
|| tinfo->goal.period != 0
|| tinfo->goal.ppr_options != 0)) {
scb->flags |= SCB_NEGOTIATE;
scb->hscb->control |= MK_MESSAGE;
}
@ -1401,19 +1400,7 @@ ahc_timeout(void *arg)
ahc_lock(ahc, &s);
/*
* Ensure that the card doesn't do anything
* behind our back. Also make sure that we
* didn't "just" miss an interrupt that would
* affect this timeout.
*/
do {
ahc_freebsd_intr(ahc);
pause_sequencer(ahc);
} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
/* Make sure the sequencer is in a safe location. */
ahc_clear_critical_section(ahc);
ahc_pause_and_flushwork(ahc);
if ((scb->flags & SCB_ACTIVE) == 0) {
/* Previous timeout took care of me already */
@ -1812,18 +1799,36 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
void
ahc_platform_free(struct ahc_softc *ahc)
{
if (ahc->platform_data != NULL) {
if (ahc->platform_data->regs != NULL)
bus_release_resource(ahc->dev_softc,
ahc->platform_data->regs_res_type,
ahc->platform_data->regs_res_id,
ahc->platform_data->regs);
struct ahc_platform_data *pdata;
if (ahc->platform_data->irq != NULL)
pdata = ahc->platform_data;
if (pdata != NULL) {
device_printf(ahc->dev_softc, "Platform free\n");
if (pdata->regs != NULL)
bus_release_resource(ahc->dev_softc,
ahc->platform_data->irq_res_type,
0, ahc->platform_data->irq);
pdata->regs_res_type,
pdata->regs_res_id,
pdata->regs);
if (pdata->irq != NULL)
bus_release_resource(ahc->dev_softc,
pdata->irq_res_type,
0, pdata->irq);
if (pdata->sim_b != NULL) {
xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL);
xpt_free_path(pdata->path_b);
xpt_bus_deregister(cam_sim_path(pdata->sim_b));
cam_sim_free(pdata->sim_b, /*free_devq*/TRUE);
}
if (pdata->sim != NULL) {
xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
xpt_free_path(pdata->path);
xpt_bus_deregister(cam_sim_path(pdata->sim));
cam_sim_free(pdata->sim, /*free_devq*/TRUE);
}
if (pdata->eh != NULL)
EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
free(ahc->platform_data, M_DEVBUF);
}
}
@ -1835,6 +1840,21 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
return (0);
}
int
ahc_detach(device_t dev)
{
struct ahc_softc *ahc;
u_long s;
device_printf(dev, "detaching device\n");
ahc = device_get_softc(dev);
ahc_lock(ahc, &s);
bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih);
ahc_unlock(ahc, &s);
ahc_free(ahc);
return (0);
}
#if UNUSED
static void
ahc_dump_targcmd(struct target_cmd *cmd)

View File

@ -43,6 +43,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h> /* For device_t */
#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
@ -165,6 +166,7 @@ struct ahc_platform_data {
struct resource *regs;
struct resource *irq;
void *ih;
eventhandler_tag eh;
};
struct scb_platform_data {
@ -451,11 +453,20 @@ void ahc_notify_xfer_settings_change(struct ahc_softc *,
void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
int /*enable*/);
/***************************** Initialization *********************************/
/************************* Initialization/Teardown ****************************/
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
void ahc_platform_free(struct ahc_softc *ahc);
int ahc_attach(struct ahc_softc *);
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
int ahc_detach(device_t);
/****************************** Interrupts ************************************/
void ahc_platform_intr(void *);
static __inline void ahc_platform_flushwork(struct ahc_softc *ahc);
static __inline void
ahc_platform_flushwork(struct ahc_softc *ahc)
{
}
/************************ Misc Function Declarations **************************/
timeout_t ahc_timeout;

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: //depot/src/aic7xxx/aic7xxx_pci.c#8 $
* $Id: //depot/src/aic7xxx/aic7xxx_pci.c#10 $
*
* $FreeBSD$
*/
@ -117,6 +117,7 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AHA_29160 0x00809005E2A09005ull
#define ID_AHA_29160_CPQ 0x00809005E2A00E11ull
#define ID_AHA_29160N 0x0080900562A09005ull
#define ID_AHA_29160C 0x0080900562209005ull
#define ID_AHA_29160B 0x00809005E2209005ull
#define ID_AHA_19160B 0x0081900562A19005ull
@ -133,6 +134,17 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AIC7810 0x1078900400000000ull
#define ID_AIC7815 0x7815900400000000ull
#define SUBID_9005_TYPE 0x000F
#define SUBID_9005_MAXRATE 0x0030
#define SUBID_9005_DISAUTOTERM 0x0040
#define SUBID_9005_LEGACYCONN 0x0080
#define SUBID_9005_SEEPTYPE 0x0300
#define SUBID_9005_NUMCHAN 0x0C00
#define SUBID_9005_MFUNCENB 0x1000
#define SUBID_9005_SCSIWIDTH 0x2000
#define SUBID_9005_PCIWIDTH 0x4000
#define SUBID_9005_SEDIFF 0x8000
static ahc_device_setup_t ahc_aic7850_setup;
static ahc_device_setup_t ahc_aic7855_setup;
static ahc_device_setup_t ahc_aic7860_setup;
@ -346,6 +358,12 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
"Adaptec 29160N Ultra160 SCSI adapter",
ahc_aic7892_setup
},
{
ID_AHA_29160C,
ID_ALL_MASK,
"Adaptec 29160C Ultra160 SCSI adapter",
ahc_aic7892_setup
},
{
ID_AHA_29160B,
ID_ALL_MASK,
@ -502,7 +520,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
}
};
const int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
#define AHC_394X_SLOT_CHANNEL_A 4
#define AHC_394X_SLOT_CHANNEL_B 5
@ -534,6 +552,16 @@ const int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
#define CACHESIZE 0x0000003ful /* only 5 bits */
#define LATTIME 0x0000ff00ul
typedef enum
{
AHC_POWER_STATE_D0,
AHC_POWER_STATE_D1,
AHC_POWER_STATE_D2,
AHC_POWER_STATE_D3
} ahc_power_state;
static void ahc_power_state_change(struct ahc_softc *ahc,
ahc_power_state new_state);
static int ahc_ext_scbram_present(struct ahc_softc *ahc);
static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
int pcheck, int fast, int large);
@ -583,6 +611,12 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
subdevice,
subvendor);
/* If the second function is not hooked up, ignore it. */
if (ahc_get_pci_function(pci) > 0
&& subvendor == 0x9005
&& (subdevice & SUBID_9005_MFUNCENB) == 0)
return (NULL);
for (i = 0; i < ahc_num_pci_devs; i++) {
entry = &ahc_pci_ident_table[i];
if (entry->full_id == (full_id & entry->id_mask))
@ -616,6 +650,8 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
if (error != 0)
return (error);
ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
/* Ensure busmastering is enabled */
command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
command |= PCIM_CMD_BUSMASTEREN;
@ -629,13 +665,19 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
return (error);
/* Remeber how the card was setup in case there is no SEEPROM */
pause_sequencer(ahc);
if ((ahc->features & AHC_ULTRA2) != 0)
our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
else
our_id = ahc_inb(ahc, SCSIID) & OID;
sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
scsiseq = ahc_inb(ahc, SCSISEQ);
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
pause_sequencer(ahc);
if ((ahc->features & AHC_ULTRA2) != 0)
our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
else
our_id = ahc_inb(ahc, SCSIID) & OID;
sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
scsiseq = ahc_inb(ahc, SCSISEQ);
} else {
sxfrctl1 = STPWEN;
our_id = 7;
scsiseq = 0;
}
error = ahc_reset(ahc);
if (error != 0)
@ -648,14 +690,11 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS);
/* Send CRC info in target mode every 4K */
ahc_outb(ahc, TARGCRCCNT, 0);
ahc_outb(ahc, TARGCRCCNT + 1, 0x10);
ahc_outb(ahc, SFUNCT, sfunct);
/* Normal mode setup */
ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN
|TARGCRCENDEN|TARGCRCCNTEN);
|TARGCRCENDEN);
}
error = ahc_pci_map_int(ahc);
@ -755,6 +794,41 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
return (0);
}
static void
ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
{
uint32_t cap;
u_int cap_offset;
/*
* Traverse the capability list looking for
* the power management capability.
*/
cap = 0;
cap_offset = ahc_pci_read_config(ahc->dev_softc,
PCIR_CAP_PTR, /*bytes*/1);
while (cap_offset != 0) {
cap = ahc_pci_read_config(ahc->dev_softc,
cap_offset, /*bytes*/4);
if ((cap & 0xFF) == 1
&& ((cap >> 16) & 0x3) > 0) {
uint32_t pm_control;
pm_control = ahc_pci_read_config(ahc->dev_softc,
cap_offset + 4,
/*bytes*/4);
pm_control &= ~0x3;
pm_control |= new_state;
ahc_pci_write_config(ahc->dev_softc,
cap_offset + 4,
pm_control, /*bytes*/2);
break;
}
cap_offset = (cap >> 8) & 0xFF;
}
}
/*
* Test for the presense of external sram in an
* "unshared" configuration.