summaryrefslogtreecommitdiffstats
path: root/sys/dev/aic7xxx
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2001-03-11 06:34:17 +0000
committergibbs <gibbs@FreeBSD.org>2001-03-11 06:34:17 +0000
commit13607586552a34e4142ab379b7b1631c43377ed2 (patch)
treec305b75a021ce5ba3a54401e2b24f0a37bf8b3ba /sys/dev/aic7xxx
parentfb0fa1fa59573248459a2e0105f13219f3df27ef (diff)
downloadFreeBSD-src-13607586552a34e4142ab379b7b1631c43377ed2.zip
FreeBSD-src-13607586552a34e4142ab379b7b1631c43377ed2.tar.gz
This is an MFC candidate.
ahc_eisa.c: Change aic7770_map_int to take an additional irq parameter. Although we can get the irq from the eisa dev under FreeBSD, we can't do this under linux, so the OSM interface must supply this. ahc_pci.c: Move ahc_power_state_change() to the OSM. This allows us to use a platform supplied function that does the same thing. -current will move to the FreeBSD native API in the near future. aic7770.c: Sync up with core changes to support Linux EISA. We now store a 2 bit primary channel number rather than a bit flag that only allows b to be the primary channel. Adjust for this change. aic7xxx.c: Namespace and staticization cleanup. All exported symbols use an "ahc_" prefix to avoid collisions with other modules. Correct a logic bug that prevented us from dropping ATN during some exceptional conditions during message processing. Take advantage of a new flag managed by the sequencer that indicates if an SCB fetch is in progress. If so, the currently selected SCB needs to be returned to the free list to prevent an SCB leak. This leak is a rarity and would only occur if a bus reset or timeout resulting in a bus reset occurred in the middle of an SCB fetch. Don't attempt to perform ULTRA transfers on ultra capable adapters missing the external precision resistor required for ultra speeds. I've never encountered an adapter configured this way, but better safe than sorry. Handle the case of 5MHz user sync rate set as "0" instead of 0x1c in scratch ram. If we lookup a period of 0 in our table (async), clear the scsi offset. aic7xxx.h: Adjust for the primary channel being represented as a 2 bit integer in the flags member of the ahc softc. Cleanup the flags definitions so that comment blocks are not cramped. Update seeprom definitions to correctly reflect the fact that the primary channel is represented as a 2 bit integer. Add AHC_ULTRA_DIASABLED softc flag to denote controllers missing the external precision resistor. aic7xxx.reg: Add DFCACHETH to the definition of DFSTATUS for completness sake. Add SEQ_FLAGS2 which currently only contains the SCB_DMA (SCB DMA in progress) flag. aic7xxx.seq: Correct a problem when one lun has a disconnected untagged transaction and another lun has disconnected tagged transactions. Just because an entry is found in the untagged table doesn't mean that it will match. If the match on the lun fails, cleanup the SCB (return it to the disconnected list or free it), and snoop for a tag message. Before this change, we reported an unsolicited reselection. This bug was introduced about a month ago during an overly aggressive optimization pass on the reselection code. When cleaning up an SCB, we can't just blindly free the SCB. In the paging case, if the SCB came off of the disconnected list, its state may never have been updated in host memory. So, check the disconnected bit in SCB_CONTROL and return the SCB to the disconnected list if appropriate. Manage the SCB_DMA flag of SEQ_FLAGS2. More carefully shutdown the S/G dma engine in all cases by using a subroutine. Supposedly not doing this can cause an arbiter hang on some ULTRA2 chips. Formatting cleanup. On some chips, at least the aic7856, the transition from MREQPEND to HDONE can take a full 4 clock cycles. Test HDONE one more time to avoid this race. We only want our FIFO hung recovery code to execute when the engine is really hung. aic7xxx_93cx6.c: Sync perforce ids. aic7xxx_freebsd.c: Adjust for the primary channel being a 2 bit integer rather than a flag for 'B' channel being the primary. Namespace cleanup. Unpause the sequencer in one error recovery path that neglected to do so. This could have caused us to perform a bus reset when a recovery message might have otherwise been successful. aic7xxx_freebsd.h: Use AHC_PCI_CONFIG for controlling compilation of PCI support consistently throughout the driver. Move ahc_power_state_change() to OSM. aic7xxx_inline.h Namespace cleanup. Adjust our interrupt handler so it will work in the edge interrupt case. We must process all interrupt sources when the interrupt fires or risk not ever getting an interrupt again. This involves marking the fact that we are relying on an edge interrupt in ahc->flags and checking for this condition in addition to the AHC_ALL_INTERRUPTS flag. This fixes hangs on the 284X and any other aic7770 installation where level interrupts are not available. aic7xxx_pci.c: Move the powerstate manipulation code into the OSM. Several OSes now provide this functionality natively. Take another shot at using the data stored in scratch ram if the SCB2 signature is correct and no SEEPROM data is available. In the past this failed if external SCB ram was configured because the memory port was locked. We now release the memory port prior to testing the values in SCB2 and re-acquire it prior to doing termination control. Adjust for new 2 bit primary channel setting. Trust the STPWLEVEL setting on v 3.X BIOSes too. Configure any 785X ID in the same fashion and assume that any device with a rev id of 1 or higher has the PCI 2.1 retry bug.
Diffstat (limited to 'sys/dev/aic7xxx')
-rw-r--r--sys/dev/aic7xxx/ahc_eisa.c2
-rw-r--r--sys/dev/aic7xxx/ahc_pci.c35
-rw-r--r--sys/dev/aic7xxx/aic7770.c29
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c182
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h86
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg7
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq169
-rw-r--r--sys/dev/aic7xxx/aic7xxx_93cx6.c2
-rw-r--r--sys/dev/aic7xxx/aic7xxx_freebsd.c25
-rw-r--r--sys/dev/aic7xxx/aic7xxx_freebsd.h17
-rw-r--r--sys/dev/aic7xxx/aic7xxx_inline.h41
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.c25
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.h17
-rw-r--r--sys/dev/aic7xxx/aic7xxx_pci.c289
14 files changed, 529 insertions, 397 deletions
diff --git a/sys/dev/aic7xxx/ahc_eisa.c b/sys/dev/aic7xxx/ahc_eisa.c
index e1262c7..79db102 100644
--- a/sys/dev/aic7xxx/ahc_eisa.c
+++ b/sys/dev/aic7xxx/ahc_eisa.c
@@ -180,7 +180,7 @@ aic7770_map_registers(struct ahc_softc *ahc)
}
int
-aic7770_map_int(struct ahc_softc *ahc)
+aic7770_map_int(struct ahc_softc *ahc, int irq)
{
int zero;
diff --git a/sys/dev/aic7xxx/ahc_pci.c b/sys/dev/aic7xxx/ahc_pci.c
index 0703145..3519dce 100644
--- a/sys/dev/aic7xxx/ahc_pci.c
+++ b/sys/dev/aic7xxx/ahc_pci.c
@@ -213,3 +213,38 @@ ahc_pci_map_int(struct ahc_softc *ahc)
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
return (0);
}
+
+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;
+ }
+}
diff --git a/sys/dev/aic7xxx/aic7770.c b/sys/dev/aic7xxx/aic7770.c
index 9c53eb4..c493da2 100644
--- a/sys/dev/aic7xxx/aic7770.c
+++ b/sys/dev/aic7xxx/aic7770.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7770.c#4 $
+ * $Id: //depot/src/aic7xxx/aic7770.c#8 $
*
* $FreeBSD$
*/
@@ -101,6 +101,8 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
struct ahc_probe_config probe_config;
int error;
u_int hostconf;
+ u_int irq;
+ u_int intdef;
ahc_init_probe_config(&probe_config);
error = entry->setup(ahc->dev_softc, &probe_config);
@@ -114,11 +116,30 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
probe_config.description = entry->name;
error = ahc_softc_init(ahc, &probe_config);
- error = aic7770_map_int(ahc);
+ error = ahc_reset(ahc);
if (error != 0)
return (error);
- error = ahc_reset(ahc);
+ /* Make sure we have a valid interrupt vector */
+ intdef = ahc_inb(ahc, INTDEF);
+ irq = intdef & VECTOR;
+ switch (irq) {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+ default:
+ printf("aic7770_config: illegal irq setting %d\n", intdef);
+ return (ENXIO);
+ }
+
+ if ((intdef & EDGE_TRIG) != 0)
+ ahc->flags |= AHC_EDGE_INTERRUPT;
+
+ error = aic7770_map_int(ahc, irq);
if (error != 0)
return (error);
@@ -135,7 +156,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
/* Get the primary channel information */
if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
- ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+ ahc->flags |= 1;
if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
ahc->flags |= AHC_USEDEFAULTS;
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c
index d0d0bcd..f6dc8c7 100644
--- a/sys/dev/aic7xxx/aic7xxx.c
+++ b/sys/dev/aic7xxx/aic7xxx.c
@@ -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#30 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.c#34 $
*
* $FreeBSD$
*/
@@ -66,9 +66,17 @@ char *ahc_chip_names[] =
"aic7892",
"aic7899"
};
-const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
+static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
-struct hard_error_entry hard_error[] = {
+/*
+ * Hardware error codes.
+ */
+struct ahc_hard_error_entry {
+ uint8_t errno;
+ char *errmesg;
+};
+
+static struct ahc_hard_error_entry ahc_hard_errors[] = {
{ ILLHADDR, "Illegal Host Access" },
{ ILLSADDR, "Illegal Sequencer Address referrenced" },
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
@@ -78,9 +86,9 @@ struct hard_error_entry hard_error[] = {
{ PCIERRSTAT, "PCI Error detected" },
{ CIOPARERR, "CIOBUS Parity Error" },
};
-const u_int num_errors = NUM_ELEMENTS(hard_error);
+static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors);
-struct phase_table_entry phase_table[] =
+static struct ahc_phase_table_entry ahc_phase_table[] =
{
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
{ P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" },
@@ -98,14 +106,14 @@ struct phase_table_entry phase_table[] =
* In most cases we only wish to itterate over real phases, so
* exclude the last element from the count.
*/
-const u_int num_phases = NUM_ELEMENTS(phase_table) - 1;
+static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1;
/*
* Valid SCSIRATE values. (p. 3-17)
* Provides a mapping of tranfer periods in ns to the proper value to
* stick in the scsixfer reg.
*/
-struct ahc_syncrate ahc_syncrates[] =
+static struct ahc_syncrate ahc_syncrates[] =
{
/* ultra2 fast/ultra period rate */
{ 0x42, 0x000, 9, "80.0" },
@@ -226,10 +234,11 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc,
* Restart the sequencer program from address zero
*/
void
-restart_sequencer(struct ahc_softc *ahc)
+ahc_restart(struct ahc_softc *ahc)
{
- pause_sequencer(ahc);
+ ahc_pause(ahc);
+
ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */
ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */
ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
@@ -252,11 +261,21 @@ restart_sequencer(struct ahc_softc *ahc)
ahc_outb(ahc, CCSGCTL, 0);
ahc_outb(ahc, CCSCBCTL, 0);
}
+ /*
+ * If we were in the process of DMA'ing SCB data into
+ * an SCB, replace that SCB on the free list. This prevents
+ * an SCB leak.
+ */
+ if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) {
+ ahc_add_curscb_to_free_list(ahc);
+ ahc_outb(ahc, SEQ_FLAGS2,
+ ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
+ }
ahc_outb(ahc, MWI_RESIDUAL, 0);
ahc_outb(ahc, SEQCTL, FASTMODE);
ahc_outb(ahc, SEQADDR0, 0);
ahc_outb(ahc, SEQADDR1, 0);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
/************************* Input/Output Queues ********************************/
@@ -337,14 +356,14 @@ ahc_handle_brkadrint(struct ahc_softc *ahc)
* We upset the sequencer :-(
* Lookup the error message
*/
- int i, error, num_errors;
+ int i;
+ int error;
error = ahc_inb(ahc, ERROR);
- num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
for (i = 0; error != 1 && i < num_errors; i++)
error >>= 1;
printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
- ahc_name(ahc), hard_error[i].errmesg,
+ ahc_name(ahc), ahc_hard_errors[i].errmesg,
ahc_inb(ahc, SEQADDR0) |
(ahc_inb(ahc, SEQADDR1) << 8));
@@ -630,7 +649,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
"Lastphase = 0x%x, Curphase = 0x%x\n",
ahc_name(ahc), devinfo.channel, devinfo.target,
lastphase, ahc_inb(ahc, SCSISIGI));
- restart_sequencer(ahc);
+ ahc_restart(ahc);
return;
}
case HOST_MSG_LOOP:
@@ -660,7 +679,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* we got here. Just punt the message.
*/
ahc_clear_intstat(ahc);
- restart_sequencer(ahc);
+ ahc_restart(ahc);
return;
}
@@ -746,13 +765,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb = ahc_lookup_scb(ahc, scbindex);
for (i = 0; i < num_phases; i++) {
- if (lastphase == phase_table[i].phase)
+ if (lastphase == ahc_phase_table[i].phase)
break;
}
ahc_print_path(ahc, scb);
printf("data overrun detected %s."
" Tag == 0x%x.\n",
- phase_table[i].phasemsg,
+ ahc_phase_table[i].phasemsg,
scb->hscb->tag);
ahc_print_path(ahc, scb);
printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n",
@@ -855,7 +874,7 @@ unpause:
* a SEQINT, so we should restart it when
* we're done.
*/
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
void
@@ -894,7 +913,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
if (status == 0) {
printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
ahc_outb(ahc, CLRINT, CLRSCSIINT);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
return;
}
}
@@ -972,10 +991,10 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
errorphase = lastphase;
for (i = 0; i < num_phases; i++) {
- if (errorphase == phase_table[i].phase)
+ if (errorphase == ahc_phase_table[i].phase)
break;
}
- mesg_out = phase_table[i].mesg_out;
+ mesg_out = ahc_phase_table[i].mesg_out;
if (scb != NULL)
ahc_print_path(ahc, scb);
else
@@ -984,7 +1003,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
scsirate = ahc_inb(ahc, SCSIRATE);
printf("parity error detected %s. "
"SEQADDR(0x%x) SCSIRATE(0x%x)\n",
- phase_table[i].phasemsg,
+ ahc_phase_table[i].phasemsg,
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8),
scsirate);
@@ -1015,7 +1034,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, MSG_OUT, mesg_out);
}
ahc_outb(ahc, CLRINT, CLRSCSIINT);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else if ((status & BUSFREE) != 0
&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
u_int lastphase;
@@ -1171,17 +1190,18 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
printf("%s: ", ahc_name(ahc));
}
for (i = 0; i < num_phases; i++) {
- if (lastphase == phase_table[i].phase)
+ if (lastphase == ahc_phase_table[i].phase)
break;
}
printf("Unexpected busfree %s\n"
"SEQADDR == 0x%x\n",
- phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0)
+ ahc_phase_table[i].phasemsg,
+ ahc_inb(ahc, SEQADDR0)
| (ahc_inb(ahc, SEQADDR1) << 8));
}
ahc_clear_msg_state(ahc);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
- restart_sequencer(ahc);
+ ahc_restart(ahc);
} else if ((status & SELTO) != 0) {
u_int scbptr;
@@ -1218,7 +1238,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_freeze_devq(ahc, scb);
}
ahc_outb(ahc, CLRINT, CLRSCSIINT);
- restart_sequencer(ahc);
+ ahc_restart(ahc);
} else {
printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
ahc_name(ahc), status);
@@ -1287,7 +1307,7 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
ahc_outb(ahc, HCNTRL, ahc->unpause);
do {
ahc_delay(200);
- } while (!sequencer_paused(ahc));
+ } while (!ahc_is_paused(ahc));
}
if (stepping) {
ahc_outb(ahc, SIMODE0, simode0);
@@ -1450,7 +1470,8 @@ 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) {
+ } else if ((ahc->features & AHC_ULTRA) != 0
+ && (ahc->flags & AHC_ULTRA_DISABLED) == 0) {
maxsync = AHC_SYNCRATE_ULTRA;
} else {
maxsync = AHC_SYNCRATE_FAST;
@@ -1667,7 +1688,7 @@ ahc_update_target_msg_request(struct ahc_softc *ahc,
if (ahc->targ_msg_req != targ_msg_req_orig) {
/* Update the message request bit for this target */
if (!paused)
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_outb(ahc, TARGET_MSG_REQUEST,
ahc->targ_msg_req & 0xFF);
@@ -1675,7 +1696,7 @@ ahc_update_target_msg_request(struct ahc_softc *ahc,
(ahc->targ_msg_req >> 8) & 0xFF);
if (!paused)
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
}
@@ -1981,6 +2002,23 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
role);
}
+struct ahc_phase_table_entry*
+ahc_lookup_phase_entry(int phase)
+{
+ struct ahc_phase_table_entry *entry;
+ int i;
+
+ /*
+ * num_phases doesn't include the default entry which
+ * will be returned if the phase doesn't match.
+ */
+ for (i = 0, entry = ahc_phase_table; i < num_phases; i++) {
+ if (phase == entry->phase)
+ break;
+ }
+ return (entry);
+}
+
void
ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
u_int lun, char channel, role_t role)
@@ -2254,7 +2292,7 @@ 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) {
+ if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) {
/*
* The target didn't care to respond to our
* message request, so clear ATN.
@@ -2875,7 +2913,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
"offset %x, options %x\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun,
- ahc->msgin_buf[3], saved_width,
+ saved_width, ahc->msgin_buf[3],
saved_offset, saved_ppr_options,
bus_width, period, offset, ppr_options);
}
@@ -2902,7 +2940,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
CAM_BDR_SENT,
"Bus Device Reset Received",
/*verbose_level*/0);
- restart_sequencer(ahc);
+ ahc_restart(ahc);
done = MSGLOOP_TERMINATED;
break;
case MSG_ABORT_TAG:
@@ -3356,29 +3394,37 @@ ahc_softc_insert(struct ahc_softc *ahc)
{
struct ahc_softc *list_ahc;
-#ifdef AHC_SUPPORT_PCI
+#if AHC_PCI_CONFIG > 0
/*
* Second Function PCI devices need to inherit some
- * settings from function 0. We assume that function 0
- * will always be found prior to function 1.
+ * settings from function 0.
*/
if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI
- && ahc_get_pci_function(ahc->dev_softc) == 1) {
+ && (ahc->features & AHC_MULTI_FUNC) != 0) {
TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
ahc_dev_softc_t list_pci;
ahc_dev_softc_t pci;
list_pci = list_ahc->dev_softc;
pci = ahc->dev_softc;
- if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)
- && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
- && ahc_get_pci_function(list_pci) == 0) {
- ahc->flags &= ~AHC_BIOS_ENABLED;
- ahc->flags |=
- list_ahc->flags & AHC_BIOS_ENABLED;
- ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
- ahc->flags |=
- list_ahc->flags & AHC_CHANNEL_B_PRIMARY;
+ if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
+ && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) {
+ struct ahc_softc *master;
+ struct ahc_softc *slave;
+
+ if (ahc_get_pci_function(list_pci) == 0) {
+ master = list_ahc;
+ slave = ahc;
+ } else {
+ master = ahc;
+ slave = list_ahc;
+ }
+ slave->flags &= ~AHC_BIOS_ENABLED;
+ slave->flags |=
+ master->flags & AHC_BIOS_ENABLED;
+ slave->flags &= ~AHC_PRIMARY_CHANNEL;
+ slave->flags |=
+ master->flags & AHC_PRIMARY_CHANNEL;
break;
}
}
@@ -3519,7 +3565,7 @@ ahc_reset(struct ahc_softc *ahc)
* It contains settings that affect termination and we don't want
* to disturb the integrity of the bus.
*/
- pause_sequencer(ahc);
+ ahc_pause(ahc);
sxfrctl1_b = 0;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
u_int sblkctl;
@@ -3957,7 +4003,7 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf)
len = sprintf(buf, "Twin Channel, A SCSI Id=%d, "
"B SCSI Id=%d, primary %c, ",
ahc->our_id, ahc->our_id_b,
- ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A');
+ (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A');
else {
const char *type;
@@ -4134,6 +4180,7 @@ ahc_init(struct ahc_softc *ahc)
}
ahc_outb(ahc, SEQ_FLAGS, 0);
+ ahc_outb(ahc, SEQ_FLAGS2, 0);
if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) {
ahc->flags |= AHC_PAGESCBS;
@@ -4218,6 +4265,8 @@ 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;
@@ -4274,6 +4323,9 @@ ahc_init(struct ahc_softc *ahc)
offset = MAX_OFFSET_ULTRA2;
} else
offset = ahc_inb(ahc, TARG_OFFSET + i);
+ if ((scsirate & ~WIDEXFER) == 0 && offset != 0)
+ /* Set to the lowest sync rate, 5MHz */
+ scsirate |= 0x1c;
maxsync = AHC_SYNCRATE_ULTRA2;
if ((ahc->features & AHC_DT) != 0)
maxsync = AHC_SYNCRATE_DT;
@@ -4302,6 +4354,8 @@ ahc_init(struct ahc_softc *ahc)
if (tinfo->user.period != 0)
tinfo->user.offset = ~0;
}
+ if (tinfo->user.period == 0)
+ tinfo->user.offset = 0;
if ((scsirate & WIDEXFER) != 0
&& (ahc->features & AHC_WIDE) != 0)
tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
@@ -4438,12 +4492,12 @@ ahc_init(struct ahc_softc *ahc)
* never settle, so don't complain if we
* fail here.
*/
- pause_sequencer(ahc);
+ ahc_pause(ahc);
for (wait = 5000;
(ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
wait--)
ahc_delay(100);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
return (0);
}
@@ -4466,7 +4520,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
intstat = 0;
do {
ahc_intr(ahc);
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_clear_critical_section(ahc);
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
break;
@@ -5397,7 +5451,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD,
channel, ROLE_UNKNOWN);
- pause_sequencer(ahc);
+ ahc_pause(ahc);
/* Make sure the sequencer is in a safe location. */
ahc_clear_critical_section(ahc);
@@ -5512,9 +5566,9 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
}
if (restart_needed)
- restart_sequencer(ahc);
+ ahc_restart(ahc);
else
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
return found;
}
@@ -5813,7 +5867,7 @@ ahc_loadseq(struct ahc_softc *ahc)
memcpy(ahc->critical_sections, cs_table, cs_count);
}
ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
- restart_sequencer(ahc);
+ ahc_restart(ahc);
if (bootverbose)
printf(" %d instructions downloaded\n", downloaded);
@@ -6215,7 +6269,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc->flags |= AHC_TARGETROLE;
if ((ahc->features & AHC_MULTIROLE) == 0)
ahc->flags &= ~AHC_INITIATORROLE;
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_loadseq(ahc);
ahc_unlock(ahc, &s);
}
@@ -6284,7 +6338,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
SLIST_INIT(&lstate->accept_tios);
SLIST_INIT(&lstate->immed_notifies);
ahc_lock(ahc, &s);
- pause_sequencer(ahc);
+ ahc_pause(ahc);
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = lstate;
ahc->enabled_luns++;
@@ -6348,7 +6402,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
scsiseq |= ENSELI;
ahc_outb(ahc, SCSISEQ, scsiseq);
}
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
@@ -6398,7 +6452,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
xpt_free_path(lstate->path);
free(lstate, M_DEVBUF);
- pause_sequencer(ahc);
+ ahc_pause(ahc);
/* Can we clean up the target too? */
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = NULL;
@@ -6451,11 +6505,11 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
printf("Configuring Initiator Mode\n");
ahc->flags &= ~AHC_TARGETROLE;
ahc->flags |= AHC_INITIATORROLE;
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_loadseq(ahc);
}
}
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
}
}
@@ -6537,11 +6591,11 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
} else {
if (!paused)
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_outb(ahc, KERNEL_TQINPOS,
ahc->tqinfifonext & HOST_TQINPOS);
if (!paused)
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
}
}
diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h
index f8e81ec..329a58d 100644
--- a/sys/dev/aic7xxx/aic7xxx.h
+++ b/sys/dev/aic7xxx/aic7xxx.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.h#18 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.h#22 $
*
* $FreeBSD$
*/
@@ -286,50 +286,56 @@ typedef enum {
* chip/controller's configuration.
*/
typedef enum {
- AHC_FNONE = 0x000,
- AHC_PAGESCBS = 0x001,/* Enable SCB paging */
- AHC_CHANNEL_B_PRIMARY = 0x002,/*
- * On twin channel adapters, probe
- * channel B first since it is the
- * primary bus.
+ AHC_FNONE = 0x000,
+ AHC_PRIMARY_CHANNEL = 0x003,/*
+ * The channel that should
+ * be probed first.
*/
- AHC_USEDEFAULTS = 0x004,/*
+ AHC_USEDEFAULTS = 0x004,/*
* For cards without an seeprom
* or a BIOS to initialize the chip's
* SRAM, we use the default target
* settings.
*/
- AHC_SEQUENCER_DEBUG = 0x008,
- AHC_SHARED_SRAM = 0x010,
- AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */
- AHC_RESET_BUS_A = 0x040,
- AHC_RESET_BUS_B = 0x080,
- AHC_EXTENDED_TRANS_A = 0x100,
- AHC_EXTENDED_TRANS_B = 0x200,
- AHC_TERM_ENB_A = 0x400,
- AHC_TERM_ENB_B = 0x800,
- AHC_INITIATORROLE = 0x1000,/*
+ AHC_SEQUENCER_DEBUG = 0x008,
+ AHC_SHARED_SRAM = 0x010,
+ AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */
+ AHC_RESET_BUS_A = 0x040,
+ AHC_RESET_BUS_B = 0x080,
+ AHC_EXTENDED_TRANS_A = 0x100,
+ AHC_EXTENDED_TRANS_B = 0x200,
+ AHC_TERM_ENB_A = 0x400,
+ AHC_TERM_ENB_B = 0x800,
+ AHC_INITIATORROLE = 0x1000,/*
* Allow initiator operations on
* this controller.
*/
- AHC_TARGETROLE = 0x2000,/*
+ AHC_TARGETROLE = 0x2000,/*
* Allow target operations on this
* controller.
*/
- AHC_NEWEEPROM_FMT = 0x4000,
- AHC_RESOURCE_SHORTAGE = 0x8000,
- AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */
- AHC_INT50_SPEEDFLEX = 0x20000,/*
+ AHC_NEWEEPROM_FMT = 0x4000,
+ AHC_RESOURCE_SHORTAGE = 0x8000,
+ AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */
+ AHC_INT50_SPEEDFLEX = 0x20000,/*
* Internal 50pin connector
* sits behind an aic3860
*/
- AHC_SCB_BTT = 0x40000,/*
+ AHC_SCB_BTT = 0x40000,/*
* The busy targets table is
* stored in SCB space rather
* than SRAM.
*/
- AHC_BIOS_ENABLED = 0x80000,
- AHC_ALL_INTERRUPTS = 0x100000
+ 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;
/*
@@ -705,32 +711,14 @@ extern struct ahc_syncrate ahc_syncrates[];
/***************************** Lookup Tables **********************************/
/*
- * Textual descriptions of the different chips indexed by chip type.
- */
-extern char *ahc_chip_names[];
-extern const u_int num_chip_names;
-
-/*
- * Hardware error codes.
- */
-struct hard_error_entry {
- uint8_t errno;
- char *errmesg;
-};
-extern struct hard_error_entry hard_error[];
-extern const u_int num_errors;
-
-/*
* Phase -> name and message out response
* to parity errors in each phase table.
*/
-struct phase_table_entry {
+struct ahc_phase_table_entry {
uint8_t phase;
uint8_t mesg_out; /* Message response to parity errors */
char *phasemsg;
};
-extern struct phase_table_entry phase_table[];
-extern const u_int num_phases;
/************************** Serial EEPROM Format ******************************/
@@ -782,7 +770,8 @@ struct seeprom_config {
#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
#define CFCLUSTERENB 0x0080 /* Cluster Enable */
-#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */
+#define CFBOOTCHAN 0x0300 /* probe this channel first */
+#define CFBOOTCHANSHIFT 8
#define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/
#define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */
#define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */
@@ -806,6 +795,7 @@ struct seeprom_config {
uint16_t res_1[10]; /* words 20-29 */
uint16_t signature; /* Signature == 0x250 */
#define CFSIGNATURE 0x250
+#define CFSIGNATURE2 0x300
uint16_t checksum; /* word 31 */
};
@@ -1137,8 +1127,10 @@ int ahc_search_disc_list(struct ahc_softc *ahc, int target,
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 restart_sequencer(struct ahc_softc *ahc);
+void ahc_restart(struct ahc_softc *ahc);
/*************************** Utility Functions ********************************/
+struct ahc_phase_table_entry*
+ ahc_lookup_phase_entry(int phase);
void ahc_compile_devinfo(struct ahc_devinfo *devinfo,
u_int our_id, u_int target,
u_int lun, char channel,
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
index 9dabe15..93e7d8e 100644
--- a/sys/dev/aic7xxx/aic7xxx.reg
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -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#12 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.reg#14 $
*
* $FreeBSD$
*/
@@ -877,6 +877,7 @@ register DFSTATUS {
address 0x094
access_mode RO
bit PRELOAD_AVAIL 0x80
+ bit DFCACHETH 0x40
bit DWORDEMP 0x20
bit MREQPEND 0x10
bit HDONE 0x08
@@ -1456,6 +1457,10 @@ scratch_ram {
size 1
}
+ SEQ_FLAGS2 {
+ size 1
+ bit SCB_DMA 0x01
+ }
/*
* These are reserved registers in the card's scratch ram. Some of
* the values are specified in the AHA2742 technical reference manual
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index b490f62..6152c77 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -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#20 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.seq#23 $
*
* $FreeBSD$
*/
@@ -88,7 +88,6 @@ BEGIN_CRITICAL
cmp KERNEL_QINPOS, A je poll_for_work_loop;
}
mov ARG_1, NEXT_QUEUED_SCB;
-END_CRITICAL
/*
* We have at least one queued SCB now and we don't have any
@@ -101,6 +100,8 @@ END_CRITICAL
/* In the non-paging case, the SCBID == hardware SCB index */
mov SCBPTR, ARG_1;
}
+ or SEQ_FLAGS2, SCB_DMA;
+END_CRITICAL
dma_queued_scb:
/*
* DMA the SCB from host ram into the current SCB location.
@@ -128,6 +129,7 @@ BEGIN_CRITICAL
} else {
inc QINPOS;
}
+ and SEQ_FLAGS2, ~SCB_DMA;
END_CRITICAL
start_waiting:
/*
@@ -692,69 +694,75 @@ sg_advance:
adc SCB_RESIDUAL_SGPTR[2],A;
adc SCB_RESIDUAL_SGPTR[3],A ret;
+if ((ahc->features & AHC_CMD_CHAN) != 0) {
+disable_ccsgen:
+ test CCSGCTL, CCSGEN jz return;
+ test CCSGCTL, CCSGDONE jz .;
+disable_ccsgen_fetch_done:
+ clr CCSGCTL;
+ test CCSGCTL, CCSGEN jnz .;
+ ret;
idle_loop:
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- /* Did we just finish fetching segs? */
- cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
+ /* Did we just finish fetching segs? */
+ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
- /* Are we actively fetching segments? */
- test CCSGCTL, CCSGEN jnz return;
+ /* 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 need any more segments?
+ */
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
- /*
- * Do we have any prefetch left???
- */
- cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
+ /*
+ * Do we have any prefetch left???
+ */
+ cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
- /*
- * Need to fetch segments, but we can only do that
- * if the command channel is completely idle. Make
- * sure we don't have an SCB prefetch going on.
- */
- test CCSCBCTL, CCSCBEN jnz return;
+ /*
+ * Need to fetch segments, but we can only do that
+ * if the command channel is completely idle. Make
+ * sure we don't have an SCB prefetch going on.
+ */
+ test CCSCBCTL, CCSCBEN jnz return;
- /*
- * We fetch a "cacheline aligned" and sized amount of data
- * so we don't end up referencing a non-existant page.
- * Cacheline aligned is in quotes because the kernel will
- * set the prefetch amount to a reasonable level if the
- * cacheline size is unknown.
- */
- mvi CCHCNT, SG_PREFETCH_CNT;
- and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
- bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
- mvi CCSGCTL, CCSGEN|CCSGRESET ret;
+ /*
+ * We fetch a "cacheline aligned" and sized amount of data
+ * so we don't end up referencing a non-existant page.
+ * Cacheline aligned is in quotes because the kernel will
+ * set the prefetch amount to a reasonable level if the
+ * cacheline size is unknown.
+ */
+ mvi CCHCNT, SG_PREFETCH_CNT;
+ and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
+ bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
+ mvi CCSGCTL, CCSGEN|CCSGRESET ret;
idle_sgfetch_complete:
- clr CCSGCTL;
- test CCSGCTL, CCSGEN jnz .;
- and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
+ call disable_ccsgen_fetch_done;
+ and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
idle_sg_avail:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- /* Does the hardware have space for another SG entry? */
- test DFSTATUS, PRELOAD_AVAIL jz return;
- bmov HADDR, CCSGRAM, 4;
- bmov SINDEX, CCSGRAM, 1;
- test SINDEX, 0x1 jz . + 2;
- xor DATA_COUNT_ODD, 0x1;
- bmov HCNT[0], SINDEX, 1;
- bmov HCNT[1], CCSGRAM, 2;
- bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
- call sg_advance;
- mov SINDEX, SCB_RESIDUAL_SGPTR[0];
- test DATA_COUNT_ODD, 0x1 jz . + 2;
- or SINDEX, ODD_SEG;
- test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
- or SINDEX, LAST_SEG;
- mov SG_CACHE_PRE, SINDEX;
- /* Load the segment by writing DFCNTRL again */
- mov DFCNTRL, DMAPARAMS;
- }
- ret;
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ /* Does the hardware have space for another SG entry? */
+ test DFSTATUS, PRELOAD_AVAIL jz return;
+ bmov HADDR, CCSGRAM, 4;
+ bmov SINDEX, CCSGRAM, 1;
+ test SINDEX, 0x1 jz . + 2;
+ xor DATA_COUNT_ODD, 0x1;
+ bmov HCNT[0], SINDEX, 1;
+ bmov HCNT[1], CCSGRAM, 2;
+ bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+ call sg_advance;
+ mov SINDEX, SCB_RESIDUAL_SGPTR[0];
+ test DATA_COUNT_ODD, 0x1 jz . + 2;
+ or SINDEX, ODD_SEG;
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+ or SINDEX, LAST_SEG;
+ mov SG_CACHE_PRE, SINDEX;
+ /* Load the segment by writing DFCNTRL again */
+ mov DFCNTRL, DMAPARAMS;
}
+ ret;
+}
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
/*
@@ -1149,12 +1157,6 @@ data_phase_finish:
if ((ahc->flags & AHC_INITIATORROLE) != 0) {
test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
-
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- /* Kill off any pending prefetch */
- clr CCSGCTL;
- test CCSGCTL, CCSGEN jnz .;
- }
}
data_phase_done:
@@ -1166,8 +1168,7 @@ data_phase_done:
*/
if ((ahc->features & AHC_CMD_CHAN) != 0) {
/* Kill off any pending prefetch */
- clr CCSGCTL;
- test CCSGCTL, CCSGEN jnz .;
+ call disable_ccsgen;
}
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
@@ -1648,12 +1649,27 @@ mesgin_identify:
if ((ahc->flags & AHC_PAGESCBS) != 0) {
mov ARG_1 call findSCB;
} else {
- mov SCBPTR, RETURN_1;
+ mov SCBPTR, ARG_1;
}
if ((ahc->flags & AHC_SCB_BTT) != 0) {
jmp setup_SCB_id_lun_okay;
} else {
- jmp setup_SCB_id_okay;
+ /*
+ * We only allow one untagged command per-target
+ * at a time. So, if the lun doesn't match, look
+ * for a tag message.
+ */
+ mov A, SCB_LUN;
+ cmp SAVED_LUN, A je setup_SCB_id_lun_okay;
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ /*
+ * findSCB removes the SCB from the
+ * disconnected list, so we must replace
+ * it there should this SCB be for another
+ * lun.
+ */
+ call cleanup_scb;
+ }
}
/*
@@ -1710,10 +1726,14 @@ setup_SCB_id_lun_okay:
test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
and SCB_CONTROL,~DISCONNECTED;
test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged;
- mov A, SCBPTR;
+ if ((ahc->flags & AHC_SCB_BTT) != 0) {
+ mov A, SCBPTR;
+ }
mvi ARG_1, SCB_LIST_NULL;
mov SAVED_SCSIID call set_busy_target;
- mov SCBPTR, A;
+ if ((ahc->flags & AHC_SCB_BTT) != 0) {
+ mov SCBPTR, A;
+ }
setup_SCB_tagged:
mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
call set_transfer_settings;
@@ -1724,7 +1744,7 @@ setup_SCB_tagged:
not_found_cleanup_scb:
if ((ahc->flags & AHC_PAGESCBS) != 0) {
- call add_scb_to_free_list;
+ call cleanup_scb;
}
not_found:
mvi NO_MATCH call set_seqint;
@@ -2056,6 +2076,7 @@ dma_scb_hang_wait:
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
/*
* The PCI module no longer intends to perform
* a PCI transaction and HDONE has not come true.
@@ -2131,6 +2152,16 @@ dma_finish:
test DFCNTRL, HDMAEN jnz .;
ret;
+/*
+ * Restore an SCB that failed to match an incoming reselection
+ * to the correct/safe state. If the SCB is for a disconnected
+ * transaction, it must be returned to the disconnected list.
+ * If it is not in the disconnected state, it must be free.
+ */
+cleanup_scb:
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list;
+ }
add_scb_to_free_list:
if ((ahc->flags & AHC_PAGESCBS) != 0) {
BEGIN_CRITICAL
diff --git a/sys/dev/aic7xxx/aic7xxx_93cx6.c b/sys/dev/aic7xxx/aic7xxx_93cx6.c
index 42078a5..684c608 100644
--- a/sys/dev/aic7xxx/aic7xxx_93cx6.c
+++ b/sys/dev/aic7xxx/aic7xxx_93cx6.c
@@ -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#5 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#7 $
*
* $FreeBSD$
*/
diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c
index 1ccf51c..8d9fb21 100644
--- a/sys/dev/aic7xxx/aic7xxx_freebsd.c
+++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c
@@ -123,7 +123,7 @@ ahc_attach(struct ahc_softc *ahc)
* declared it the primary channel.
*/
if ((ahc->features & AHC_TWIN) != 0
- && (ahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) {
+ && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
bus_id = 1;
bus_id2 = 0;
} else {
@@ -214,7 +214,7 @@ ahc_attach(struct ahc_softc *ahc)
fail:
if ((ahc->features & AHC_TWIN) != 0
- && (ahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) {
+ && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
ahc->platform_data->sim_b = sim;
ahc->platform_data->path_b = path;
ahc->platform_data->sim = sim2;
@@ -1239,12 +1239,12 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
scb->flags |= SCB_ACTIVE;
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
- pause_sequencer(ahc);
+ ahc_pause(ahc);
if ((ahc->flags & AHC_PAGESCBS) == 0)
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
ahc_outb(ahc, SCB_TAG, scb->hscb->tag);
ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
ahc_queue_scb(ahc, scb);
}
@@ -1423,7 +1423,7 @@ ahc_timeout(void *arg)
/* Previous timeout took care of me already */
printf("%s: Timedout SCB already complete. "
"Interrupts may not be functioning.\n", ahc_name(ahc));
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1440,11 +1440,7 @@ ahc_timeout(void *arg)
*/
last_phase = ahc_inb(ahc, LASTPHASE);
- for (i = 0; i < num_phases; i++) {
- if (last_phase == phase_table[i].phase)
- break;
- }
- printf("%s", phase_table[i].phasemsg);
+ printf("%s", ahc_lookup_phase_entry(last_phase)->phasemsg);
printf(", SEQADDR == 0x%x\n",
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
@@ -1534,6 +1530,7 @@ bus_reset:
ccbh = &scb->io_ctx->ccb_h;
scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, scb, newtimeout);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1552,7 +1549,7 @@ bus_reset:
ahc_done(ahc, scb);
/* Will clear us from the bus */
- restart_sequencer(ahc);
+ ahc_restart(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1565,7 +1562,7 @@ bus_reset:
active_scb->flags |= SCB_DEVICE_RESET;
active_scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, (caddr_t)active_scb, 2 * hz);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
int disconnected;
@@ -1579,7 +1576,7 @@ bus_reset:
/* Hung target selection. Goto busfree */
printf("%s: Hung target selection\n",
ahc_name(ahc));
- restart_sequencer(ahc);
+ ahc_restart(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1659,7 +1656,7 @@ bus_reset:
ahc_outb(ahc, SCBPTR, saved_scbptr);
scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, (caddr_t)scb, 2 * hz);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
/* Go "immediatly" to the bus reset */
/* This shouldn't happen */
diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.h b/sys/dev/aic7xxx/aic7xxx_freebsd.h
index 1aeba2d..59b6e97 100644
--- a/sys/dev/aic7xxx/aic7xxx_freebsd.h
+++ b/sys/dev/aic7xxx/aic7xxx_freebsd.h
@@ -49,7 +49,7 @@
#include <sys/queue.h>
#if NPCI > 0
-#define AHC_SUPPORT_PCI 1
+#define AHC_PCI_CONFIG 1
#ifdef AHC_ALLOW_MEMIO
#include <machine/bus_memio.h>
#endif
@@ -404,7 +404,7 @@ ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb)
}
/********************************** PCI ***************************************/
-#ifdef AHC_SUPPORT_PCI
+#ifdef AHC_PCI_CONFIG
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
int reg, int width);
static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
@@ -446,10 +446,21 @@ ahc_get_pci_bus(ahc_dev_softc_t pci)
{
return (pci_get_bus(pci));
}
+
+typedef enum
+{
+ AHC_POWER_STATE_D0,
+ AHC_POWER_STATE_D1,
+ AHC_POWER_STATE_D2,
+ AHC_POWER_STATE_D3
+} ahc_power_state;
+
+void ahc_power_state_change(struct ahc_softc *ahc,
+ ahc_power_state new_state);
#endif
/******************************** VL/EISA *************************************/
int aic7770_map_registers(struct ahc_softc *ahc);
-int aic7770_map_int(struct ahc_softc *ahc);
+int aic7770_map_int(struct ahc_softc *ahc, int irq);
/********************************* Debug **************************************/
static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h
index a13e376..16edaba 100644
--- a/sys/dev/aic7xxx/aic7xxx_inline.h
+++ b/sys/dev/aic7xxx/aic7xxx_inline.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#15 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#17 $
*
* $FreeBSD$
*/
@@ -37,10 +37,10 @@
#define _AIC7XXX_INLINE_H_
/************************* Sequencer Execution Control ************************/
-static __inline int sequencer_paused(struct ahc_softc *ahc);
+static __inline int ahc_is_paused(struct ahc_softc *ahc);
static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
-static __inline void pause_sequencer(struct ahc_softc *ahc);
-static __inline void unpause_sequencer(struct ahc_softc *ahc);
+static __inline void ahc_pause(struct ahc_softc *ahc);
+static __inline void ahc_unpause(struct ahc_softc *ahc);
/*
* Work around any chip bugs related to halting sequencer execution.
@@ -62,7 +62,7 @@ ahc_pause_bug_fix(struct ahc_softc *ahc)
* Returns non-zero status if the sequencer is stopped.
*/
static __inline int
-sequencer_paused(struct ahc_softc *ahc)
+ahc_is_paused(struct ahc_softc *ahc)
{
return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
}
@@ -75,7 +75,7 @@ sequencer_paused(struct ahc_softc *ahc)
* for critical sections.
*/
static __inline void
-pause_sequencer(struct ahc_softc *ahc)
+ahc_pause(struct ahc_softc *ahc)
{
ahc_outb(ahc, HCNTRL, ahc->pause);
@@ -83,7 +83,7 @@ pause_sequencer(struct ahc_softc *ahc)
* Since the sequencer can disable pausing in a critical section, we
* must loop until it actually stops.
*/
- while (sequencer_paused(ahc) == 0)
+ while (ahc_is_paused(ahc) == 0)
;
ahc_pause_bug_fix(ahc);
@@ -100,7 +100,7 @@ pause_sequencer(struct ahc_softc *ahc)
* condition.
*/
static __inline void
-unpause_sequencer(struct ahc_softc *ahc)
+ahc_unpause(struct ahc_softc *ahc)
{
if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
ahc_outb(ahc, HCNTRL, ahc->unpause);
@@ -345,10 +345,10 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
} else {
if ((ahc->features & AHC_AUTOPAUSE) == 0)
- pause_sequencer(ahc);
+ ahc_pause(ahc);
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
if ((ahc->features & AHC_AUTOPAUSE) == 0)
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
}
@@ -412,14 +412,23 @@ ahc_intr(struct ahc_softc *ahc)
* completion queues. This avoids a costly PCI bus read in
* most cases.
*/
- intstat = 0;
- if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
+ if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
+ && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
intstat = CMDCMPLT;
-
- if ((intstat & INT_PEND) == 0
- || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) {
-
+ else {
intstat = ahc_inb(ahc, INTSTAT);
+ /*
+ * We can't generate queuestat once above
+ * or we are exposed to a race when our
+ * interrupt is shared with another device.
+ * if instat showed a command complete interrupt,
+ * but our first generation of queue stat
+ * "just missed" the delivery of this transaction,
+ * we would clear the command complete interrupt
+ * below without ever servicing the completed
+ * command.
+ */
+ queuestat = ahc_check_cmdcmpltqueues(ahc);
#if AHC_PCI_CONFIG > 0
if (ahc->unsolicited_ints > 500
&& (ahc->chip & AHC_PCI) != 0
diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c
index 1ccf51c..8d9fb21 100644
--- a/sys/dev/aic7xxx/aic7xxx_osm.c
+++ b/sys/dev/aic7xxx/aic7xxx_osm.c
@@ -123,7 +123,7 @@ ahc_attach(struct ahc_softc *ahc)
* declared it the primary channel.
*/
if ((ahc->features & AHC_TWIN) != 0
- && (ahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) {
+ && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
bus_id = 1;
bus_id2 = 0;
} else {
@@ -214,7 +214,7 @@ ahc_attach(struct ahc_softc *ahc)
fail:
if ((ahc->features & AHC_TWIN) != 0
- && (ahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) {
+ && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
ahc->platform_data->sim_b = sim;
ahc->platform_data->path_b = path;
ahc->platform_data->sim = sim2;
@@ -1239,12 +1239,12 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
scb->flags |= SCB_ACTIVE;
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
- pause_sequencer(ahc);
+ ahc_pause(ahc);
if ((ahc->flags & AHC_PAGESCBS) == 0)
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
ahc_outb(ahc, SCB_TAG, scb->hscb->tag);
ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
ahc_queue_scb(ahc, scb);
}
@@ -1423,7 +1423,7 @@ ahc_timeout(void *arg)
/* Previous timeout took care of me already */
printf("%s: Timedout SCB already complete. "
"Interrupts may not be functioning.\n", ahc_name(ahc));
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1440,11 +1440,7 @@ ahc_timeout(void *arg)
*/
last_phase = ahc_inb(ahc, LASTPHASE);
- for (i = 0; i < num_phases; i++) {
- if (last_phase == phase_table[i].phase)
- break;
- }
- printf("%s", phase_table[i].phasemsg);
+ printf("%s", ahc_lookup_phase_entry(last_phase)->phasemsg);
printf(", SEQADDR == 0x%x\n",
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
@@ -1534,6 +1530,7 @@ bus_reset:
ccbh = &scb->io_ctx->ccb_h;
scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, scb, newtimeout);
+ ahc_unpause(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1552,7 +1549,7 @@ bus_reset:
ahc_done(ahc, scb);
/* Will clear us from the bus */
- restart_sequencer(ahc);
+ ahc_restart(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1565,7 +1562,7 @@ bus_reset:
active_scb->flags |= SCB_DEVICE_RESET;
active_scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, (caddr_t)active_scb, 2 * hz);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
int disconnected;
@@ -1579,7 +1576,7 @@ bus_reset:
/* Hung target selection. Goto busfree */
printf("%s: Hung target selection\n",
ahc_name(ahc));
- restart_sequencer(ahc);
+ ahc_restart(ahc);
ahc_unlock(ahc, &s);
return;
}
@@ -1659,7 +1656,7 @@ bus_reset:
ahc_outb(ahc, SCBPTR, saved_scbptr);
scb->io_ctx->ccb_h.timeout_ch =
timeout(ahc_timeout, (caddr_t)scb, 2 * hz);
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
} else {
/* Go "immediatly" to the bus reset */
/* This shouldn't happen */
diff --git a/sys/dev/aic7xxx/aic7xxx_osm.h b/sys/dev/aic7xxx/aic7xxx_osm.h
index 1aeba2d..59b6e97 100644
--- a/sys/dev/aic7xxx/aic7xxx_osm.h
+++ b/sys/dev/aic7xxx/aic7xxx_osm.h
@@ -49,7 +49,7 @@
#include <sys/queue.h>
#if NPCI > 0
-#define AHC_SUPPORT_PCI 1
+#define AHC_PCI_CONFIG 1
#ifdef AHC_ALLOW_MEMIO
#include <machine/bus_memio.h>
#endif
@@ -404,7 +404,7 @@ ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb)
}
/********************************** PCI ***************************************/
-#ifdef AHC_SUPPORT_PCI
+#ifdef AHC_PCI_CONFIG
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
int reg, int width);
static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
@@ -446,10 +446,21 @@ ahc_get_pci_bus(ahc_dev_softc_t pci)
{
return (pci_get_bus(pci));
}
+
+typedef enum
+{
+ AHC_POWER_STATE_D0,
+ AHC_POWER_STATE_D1,
+ AHC_POWER_STATE_D2,
+ AHC_POWER_STATE_D3
+} ahc_power_state;
+
+void ahc_power_state_change(struct ahc_softc *ahc,
+ ahc_power_state new_state);
#endif
/******************************** VL/EISA *************************************/
int aic7770_map_registers(struct ahc_softc *ahc);
-int aic7770_map_int(struct ahc_softc *ahc);
+int aic7770_map_int(struct ahc_softc *ahc, int irq);
/********************************* Debug **************************************/
static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c
index 15cf078..02a73d4 100644
--- a/sys/dev/aic7xxx/aic7xxx_pci.c
+++ b/sys/dev/aic7xxx/aic7xxx_pci.c
@@ -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#16 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#19 $
*
* $FreeBSD$
*/
@@ -63,84 +63,84 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
return (id);
}
-#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
-#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
-#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull
-#define ID_9005_SISL_MASK 0x000FFFFF00000000ull
-#define ID_9005_SISL_ID 0x0005900500000000ull
-#define ID_AIC7850 0x5078900400000000ull
-#define ID_AHA_2910_15_20_30C 0x5078900478509004ull
-#define ID_AIC7855 0x5578900400000000ull
-#define ID_AIC7859 0x3860900400000000ull
-#define ID_AHA_2930CU 0x3860900438699004ull
-#define ID_AIC7860 0x6078900400000000ull
-#define ID_AIC7860C 0x6078900478609004ull
-#define ID_AHA_1480A 0x6075900400000000ull
-#define ID_AHA_2940AU_0 0x6178900400000000ull
-#define ID_AHA_2940AU_1 0x6178900478619004ull
-#define ID_AHA_2940AU_CN 0x2178900478219004ull
-#define ID_AHA_2930C_VAR 0x6038900438689004ull
-
-#define ID_AIC7870 0x7078900400000000ull
-#define ID_AHA_2940 0x7178900400000000ull
-#define ID_AHA_3940 0x7278900400000000ull
-#define ID_AHA_398X 0x7378900400000000ull
-#define ID_AHA_2944 0x7478900400000000ull
-#define ID_AHA_3944 0x7578900400000000ull
-#define ID_AHA_4944 0x7678900400000000ull
-
-#define ID_AIC7880 0x8078900400000000ull
-#define ID_AIC7880_B 0x8078900478809004ull
-#define ID_AHA_2940U 0x8178900400000000ull
-#define ID_AHA_3940U 0x8278900400000000ull
-#define ID_AHA_2944U 0x8478900400000000ull
-#define ID_AHA_3944U 0x8578900400000000ull
-#define ID_AHA_398XU 0x8378900400000000ull
-#define ID_AHA_4944U 0x8678900400000000ull
-#define ID_AHA_2940UB 0x8178900478819004ull
-#define ID_AHA_2930U 0x8878900478889004ull
-#define ID_AHA_2940U_PRO 0x8778900478879004ull
-#define ID_AHA_2940U_CN 0x0078900478009004ull
-
-#define ID_AIC7895 0x7895900478959004ull
-#define ID_AIC7895_ARO 0x7890900478939004ull
-#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull
-#define ID_AHA_2940U_DUAL 0x7895900478919004ull
-#define ID_AHA_3940AU 0x7895900478929004ull
-#define ID_AHA_3944AU 0x7895900478949004ull
-
-#define ID_AIC7890 0x001F9005000F9005ull
-#define ID_AIC7890_ARO 0x00139005000F9005ull
-#define ID_AAA_131U2 0x0013900500039005ull
-#define ID_AHA_2930U2 0x0011900501819005ull
-#define ID_AHA_2940U2B 0x00109005A1009005ull
-#define ID_AHA_2940U2_OEM 0x0010900521809005ull
-#define ID_AHA_2940U2 0x00109005A1809005ull
-#define ID_AHA_2950U2B 0x00109005E1009005ull
-
-#define ID_AIC7892 0x008F9005FFFF9005ull
-#define ID_AIC7892_ARO 0x00839005FFFF9005ull
-#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
-
-#define ID_AIC7896 0x005F9005FFFF9005ull
-#define ID_AIC7896_ARO 0x00539005FFFF9005ull
-#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull
-#define ID_AHA_3950U2B_1 0x00509005F5009005ull
-#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull
-#define ID_AHA_3950U2D_1 0x00519005B5009005ull
-
-#define ID_AIC7899 0x00CF9005FFFF9005ull
-#define ID_AIC7899_ARO 0x00C39005FFFF9005ull
-#define ID_AHA_3960D 0x00C09005F6209005ull /* AKA AHA-39160 */
-#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull
-
-#define ID_AIC7810 0x1078900400000000ull
-#define ID_AIC7815 0x7815900400000000ull
+#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull
+#define ID_9005_SISL_MASK 0x000FFFFF00000000ull
+#define ID_9005_SISL_ID 0x0005900500000000ull
+#define ID_AIC7850 0x5078900400000000ull
+#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull
+#define ID_AIC7855 0x5578900400000000ull
+#define ID_AIC7859 0x3860900400000000ull
+#define ID_AHA_2930CU 0x3860900438699004ull
+#define ID_AIC7860 0x6078900400000000ull
+#define ID_AIC7860C 0x6078900478609004ull
+#define ID_AHA_1480A 0x6075900400000000ull
+#define ID_AHA_2940AU_0 0x6178900400000000ull
+#define ID_AHA_2940AU_1 0x6178900478619004ull
+#define ID_AHA_2940AU_CN 0x2178900478219004ull
+#define ID_AHA_2930C_VAR 0x6038900438689004ull
+
+#define ID_AIC7870 0x7078900400000000ull
+#define ID_AHA_2940 0x7178900400000000ull
+#define ID_AHA_3940 0x7278900400000000ull
+#define ID_AHA_398X 0x7378900400000000ull
+#define ID_AHA_2944 0x7478900400000000ull
+#define ID_AHA_3944 0x7578900400000000ull
+#define ID_AHA_4944 0x7678900400000000ull
+
+#define ID_AIC7880 0x8078900400000000ull
+#define ID_AIC7880_B 0x8078900478809004ull
+#define ID_AHA_2940U 0x8178900400000000ull
+#define ID_AHA_3940U 0x8278900400000000ull
+#define ID_AHA_2944U 0x8478900400000000ull
+#define ID_AHA_3944U 0x8578900400000000ull
+#define ID_AHA_398XU 0x8378900400000000ull
+#define ID_AHA_4944U 0x8678900400000000ull
+#define ID_AHA_2940UB 0x8178900478819004ull
+#define ID_AHA_2930U 0x8878900478889004ull
+#define ID_AHA_2940U_PRO 0x8778900478879004ull
+#define ID_AHA_2940U_CN 0x0078900478009004ull
+
+#define ID_AIC7895 0x7895900478959004ull
+#define ID_AIC7895_ARO 0x7890900478939004ull
+#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull
+#define ID_AHA_2940U_DUAL 0x7895900478919004ull
+#define ID_AHA_3940AU 0x7895900478929004ull
+#define ID_AHA_3944AU 0x7895900478949004ull
+
+#define ID_AIC7890 0x001F9005000F9005ull
+#define ID_AIC7890_ARO 0x00139005000F9005ull
+#define ID_AAA_131U2 0x0013900500039005ull
+#define ID_AHA_2930U2 0x0011900501819005ull
+#define ID_AHA_2940U2B 0x00109005A1009005ull
+#define ID_AHA_2940U2_OEM 0x0010900521809005ull
+#define ID_AHA_2940U2 0x00109005A1809005ull
+#define ID_AHA_2950U2B 0x00109005E1009005ull
+
+#define ID_AIC7892 0x008F9005FFFF9005ull
+#define ID_AIC7892_ARO 0x00839005FFFF9005ull
+#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
+
+#define ID_AIC7896 0x005F9005FFFF9005ull
+#define ID_AIC7896_ARO 0x00539005FFFF9005ull
+#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull
+#define ID_AHA_3950U2B_1 0x00509005F5009005ull
+#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull
+#define ID_AHA_3950U2D_1 0x00519005B5009005ull
+
+#define ID_AIC7899 0x00CF9005FFFF9005ull
+#define ID_AIC7899_ARO 0x00C39005FFFF9005ull
+#define ID_AHA_3960D 0x00C09005F6209005ull
+#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull
+
+#define ID_AIC7810 0x1078900400000000ull
+#define ID_AIC7815 0x7815900400000000ull
#define DEVID_9005_TYPE(id) ((id) & 0xF)
#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */
@@ -212,8 +212,7 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000
#define SUBID_9005_CARD_SEDIFF_MASK 0x8000
-static ahc_device_setup_t ahc_aic7850_setup;
-static ahc_device_setup_t ahc_aic7855_setup;
+static ahc_device_setup_t ahc_aic785X_setup;
static ahc_device_setup_t ahc_aic7860_setup;
static ahc_device_setup_t ahc_apa1480_setup;
static ahc_device_setup_t ahc_aic7870_setup;
@@ -239,10 +238,10 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
{
/* aic7850 based controllers */
{
- ID_AHA_2910_15_20_30C,
+ ID_AHA_2902_04_10_15_20_30C,
ID_ALL_MASK,
- "Adaptec 2910/15/20/30C SCSI adapter",
- ahc_aic7850_setup
+ "Adaptec 2902/04/10/15/20/30C SCSI adapter",
+ ahc_aic785X_setup
},
/* aic7860 based controllers */
{
@@ -544,13 +543,13 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
ID_AIC7850 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
"Adaptec aic7850 SCSI adapter",
- ahc_aic7850_setup
+ ahc_aic785X_setup
},
{
ID_AIC7855 & ID_DEV_VENDOR_MASK,
ID_DEV_VENDOR_MASK,
"Adaptec aic7855 SCSI adapter",
- ahc_aic7855_setup
+ ahc_aic785X_setup
},
{
ID_AIC7859 & ID_DEV_VENDOR_MASK,
@@ -636,6 +635,7 @@ const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
#define DEVCONFIG 0x40
#define SCBSIZE32 0x00010000ul /* aic789X only */
+#define REXTVALID 0x00001000ul /* ultra cards only */
#define MPORTMODE 0x00000400ul /* aic7870 only */
#define RAMPSM 0x00000200ul /* aic7870 only */
#define VOLSENSE 0x00000100ul
@@ -652,16 +652,6 @@ const u_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);
@@ -771,7 +761,7 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
/* Remeber how the card was setup in case there is no SEEPROM */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
- pause_sequencer(ahc);
+ ahc_pause(ahc);
if ((ahc->features & AHC_ULTRA2) != 0)
our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
else
@@ -887,6 +877,20 @@ 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)
@@ -900,41 +904,6 @@ 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.
@@ -1184,32 +1153,37 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
}
sd.sd_chip = C56_66;
}
+ release_seeprom(&sd);
}
-#if 0
if (!have_seeprom) {
/*
* Pull scratch ram settings and treat them as
* if they are the contents of an seeprom if
* the 'ADPT' signature is found in SCB2.
+ * We manually compose the data as 16bit values
+ * to avoid endian issues.
*/
ahc_outb(ahc, SCBPTR, 2);
if (ahc_inb(ahc, SCB_BASE) == 'A'
&& ahc_inb(ahc, SCB_BASE + 1) == 'D'
&& ahc_inb(ahc, SCB_BASE + 2) == 'P'
&& ahc_inb(ahc, SCB_BASE + 3) == 'T') {
- uint8_t *sc_bytes;
+ uint16_t *sc_data;
int i;
- sc_bytes = (uint8_t *)&sc;
- for (i = 0; i < 64; i++)
- sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i);
- /* Byte 0x1c is stored in byte 4 of SCB2 */
- sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4);
+ sc_data = (uint16_t *)&sc;
+ for (i = 0; i < 32; i++) {
+ uint16_t val;
+ int j;
+
+ j = i * 2;
+ val = ahc_inb(ahc, SRAM_BASE + j)
+ | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
+ }
have_seeprom = verify_cksum(&sc);
}
}
-#endif
if (!have_seeprom) {
if (bootverbose)
@@ -1295,9 +1269,8 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if (sc.adapter_control & CFRESETB)
scsi_conf |= RESET_SCSI;
- if ((sc.adapter_control & CFCHNLBPRIMARY) != 0
- && (ahc->features & AHC_MULTI_FUNC) != 0)
- ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+ ahc->flags |=
+ (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
if (sc.bios_control & CFEXTEND)
ahc->flags |= AHC_EXTENDED_TRANS_A;
@@ -1312,7 +1285,8 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
ultraenb = 0;
}
- if (sc.signature == CFSIGNATURE) {
+ if (sc.signature == CFSIGNATURE
+ || sc.signature == CFSIGNATURE2) {
uint32_t devconfig;
/* Honor the STPWLEVEL settings */
@@ -1356,10 +1330,11 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
have_autoterm = FALSE;
}
- if (have_autoterm)
+ if (have_autoterm) {
+ acquire_seeprom(ahc, &sd);
configure_termination(ahc, &sd, adapter_control, sxfrctl1);
-
- release_seeprom(&sd);
+ release_seeprom(&sd);
+ }
}
static void
@@ -1800,28 +1775,22 @@ ahc_pci_intr(struct ahc_softc *ahc)
ahc_outb(ahc, CLRINT, CLRPARERR);
}
- unpause_sequencer(ahc);
+ ahc_unpause(ahc);
}
static int
-ahc_aic7850_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic785X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
{
+ uint8_t rev;
+
probe_config->channel = 'A';
probe_config->chip = AHC_AIC7850;
probe_config->features = AHC_AIC7850_FE;
probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
| AHC_PCI_MWI_BUG;
- return (0);
-}
-
-static int
-ahc_aic7855_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
-{
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7855;
- probe_config->features = AHC_AIC7855_FE;
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
- | AHC_PCI_MWI_BUG;
+ rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+ if (rev >= 1)
+ probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
return (0);
}
OpenPOWER on IntegriCloud