summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2000-07-18 20:12:14 +0000
committergibbs <gibbs@FreeBSD.org>2000-07-18 20:12:14 +0000
commit3c297571e4ab2eaa48b8a668018bf98fa7c09bb1 (patch)
treeb2436e0f6914c3a852612307f511e9d4bc77fe65 /sys
parentaa1aa491738eccdbcafc0de36ae876e8a36262c5 (diff)
downloadFreeBSD-src-3c297571e4ab2eaa48b8a668018bf98fa7c09bb1.zip
FreeBSD-src-3c297571e4ab2eaa48b8a668018bf98fa7c09bb1.tar.gz
o Convert to <inttypes.h> style fixed sized types to facilitate porting to
other systems. o Normalize copyright text. o Clean up probe code function interfaces by passing around a single structure of common arguments instead of passing "too many" args in each function call. o Add support for the AAA-131 as a SCSI adapter. o Add support for the AHA-4944 courtesy of "Matthew N. Dodd" <winter@jurai.net o Correct manual termination support for PCI cards. The bit definitions for manual termination control in the SEEPROM were incorrect. o Add support for extracting NVRAM information from SCB 2 for BIOSen that use this mechanism to pass this data to OS drivers. o Properly set the STPWLEVEL bit in PCI config space based on the setting in an SEEPROM. o Go back to useing 32byte SCBs for all controllers. The current firmware allows us to embed 12byte cdbs on all controllers in a 32byte SCB, and larger cdbs are rarely used, so it is a better use of this space to offer more SCBs (32). o Add support for U160 transfers. o Add an idle loop executed during data transfers that prefetches S/G segments on controllers that have a secondary DMA engine (aic789X). o Improve the performance of reselections by avoiding an extra one byte DMA in the case of an SCB lookup miss for the reselecting target. We now keep a 16byte "untagged target" array on the card for dealing with untagged reselections. If the controller has external SCB ram and can support 64byte SCBs, then we use an "untagged target/lun" array to maximize concurrency. Without external SCB ram, the controller is limited to one untagged transaction per target, auto-request sense operations excluded. o Correct the setup of the STPWEN bit in SXFRCTL1. This control line is tri-stated until set to one, so set it to one and then set it to the desired value. o Add tagged queuing support to our target role implementation. o Handle the common cases of the ignore wide residue message in firmware. o Add preliminary support for 39bit addressing. o Add support for assembling on big-endian machines. Big-endian support is not complete in the driver. o Correctly remove SCBs in the waiting for selection queue when freezing a device queue. o Now that we understand more about the autoflush bug on the aic7890, only use the workaround on devices that need it. o Add a workaround for the "aic7890 hangs the system when you attempt to pause it" problem. We can now pause the aic7890 safely regardless of what instruction it is executing.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/aic7xxx/93cx6.c6
-rw-r--r--sys/dev/aic7xxx/93cx6.h16
-rw-r--r--sys/dev/aic7xxx/ahc_eisa.c46
-rw-r--r--sys/dev/aic7xxx/ahc_pci.c587
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c1960
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h440
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg174
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq1198
-rw-r--r--sys/dev/aic7xxx/aic7xxx_93cx6.c6
-rw-r--r--sys/dev/aic7xxx/aic7xxx_93cx6.h16
-rw-r--r--sys/dev/aic7xxx/aicasm.c38
-rw-r--r--sys/dev/aic7xxx/aicasm.h3
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm.c38
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm.h3
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_gram.y38
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_insformat.h (renamed from sys/dev/aic7xxx/sequencer.h)42
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_scan.l6
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_symbol.c5
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_symbol.h11
-rw-r--r--sys/dev/aic7xxx/aicasm_gram.y38
-rw-r--r--sys/dev/aic7xxx/aicasm_insformat.h123
-rw-r--r--sys/dev/aic7xxx/aicasm_scan.l6
-rw-r--r--sys/dev/aic7xxx/aicasm_symbol.c5
-rw-r--r--sys/dev/aic7xxx/aicasm_symbol.h11
24 files changed, 2973 insertions, 1843 deletions
diff --git a/sys/dev/aic7xxx/93cx6.c b/sys/dev/aic7xxx/93cx6.c
index 06e547b..62a4aee 100644
--- a/sys/dev/aic7xxx/93cx6.c
+++ b/sys/dev/aic7xxx/93cx6.c
@@ -89,14 +89,14 @@ static struct seeprom_cmd {
int
read_seeprom(sd, buf, start_addr, count)
struct seeprom_descriptor *sd;
- u_int16_t *buf;
+ uint16_t *buf;
bus_size_t start_addr;
bus_size_t count;
{
int i = 0;
u_int k = 0;
- u_int16_t v;
- u_int8_t temp;
+ uint16_t v;
+ uint8_t temp;
/*
* Read the requested registers of the seeprom. The loop
diff --git a/sys/dev/aic7xxx/93cx6.h b/sys/dev/aic7xxx/93cx6.h
index 7875032..8fd7bb9 100644
--- a/sys/dev/aic7xxx/93cx6.h
+++ b/sys/dev/aic7xxx/93cx6.h
@@ -16,7 +16,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -52,12 +52,12 @@ struct seeprom_descriptor {
bus_size_t sd_status_offset;
bus_size_t sd_dataout_offset;
seeprom_chip_t sd_chip;
- u_int16_t sd_MS;
- u_int16_t sd_RDY;
- u_int16_t sd_CS;
- u_int16_t sd_CK;
- u_int16_t sd_DO;
- u_int16_t sd_DI;
+ uint16_t sd_MS;
+ uint16_t sd_RDY;
+ uint16_t sd_CS;
+ uint16_t sd_CK;
+ uint16_t sd_DO;
+ uint16_t sd_DI;
};
/*
@@ -85,7 +85,7 @@ struct seeprom_descriptor {
#define SEEPROM_DATA_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
-int read_seeprom(struct seeprom_descriptor *sd, u_int16_t *buf,
+int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
bus_size_t start_addr, bus_size_t count);
#endif /* _KERNEL */
diff --git a/sys/dev/aic7xxx/ahc_eisa.c b/sys/dev/aic7xxx/ahc_eisa.c
index 4e91eed..1e0e16a 100644
--- a/sys/dev/aic7xxx/ahc_eisa.c
+++ b/sys/dev/aic7xxx/ahc_eisa.c
@@ -90,10 +90,10 @@ static int
aic7770_probe(device_t dev)
{
const char *desc;
- u_int32_t iobase;
- u_int32_t irq;
- u_int8_t intdef;
- u_int8_t hcntrl;
+ uint32_t iobase;
+ uint32_t irq;
+ uint8_t intdef;
+ uint8_t hcntrl;
int shared;
desc = aic7770_match(eisa_get_id(dev));
@@ -138,7 +138,7 @@ aic7770_probe(device_t dev)
static int
aic7770_attach(device_t dev)
{
- ahc_chip chip;
+ struct ahc_probe_config probe_config;
bus_dma_tag_t parent_dmat;
struct ahc_softc *ahc;
struct resource *io;
@@ -147,20 +147,27 @@ aic7770_attach(device_t dev)
rid = 0;
io = NULL;
ahc = NULL;
+ ahc_init_probe_config(&probe_config);
switch (eisa_get_id(dev)) {
case EISA_DEVICE_ID_ADAPTEC_274x:
case EISA_DEVICE_ID_ADAPTEC_AIC7770:
- chip = AHC_AIC7770|AHC_EISA;
+ probe_config.chip = AHC_AIC7770|AHC_EISA;
break;
case EISA_DEVICE_ID_ADAPTEC_284xB:
case EISA_DEVICE_ID_ADAPTEC_284x:
- chip = AHC_AIC7770|AHC_VL;
+ probe_config.chip = AHC_AIC7770|AHC_VL;
break;
default:
printf("aic7770_attach: Unknown device type!\n");
goto bad;
}
+ probe_config.description = aic7770_match(eisa_get_id(dev));
+ probe_config.channel = 'A';
+ probe_config.channel_b = 'B';
+ probe_config.features = AHC_AIC7770_FE;
+ probe_config.bugs |= AHC_TMODE_WIDEODD_BUG;
+ probe_config.flags |= AHC_PAGESCBS;
/* XXX Should be a child of the EISA bus dma tag */
error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
/*boundary*/0,
@@ -186,14 +193,11 @@ aic7770_attach(device_t dev)
}
if (!(ahc = ahc_alloc(dev, io, SYS_RES_IOPORT, rid,
- parent_dmat, chip, AHC_AIC7770_FE, AHC_FNONE,
- NULL)))
+ parent_dmat, &probe_config, NULL)))
goto bad;
io = NULL;
- ahc->channel = 'A';
- ahc->channel_b = 'B';
if (ahc_reset(ahc) != 0) {
goto bad;
}
@@ -228,7 +232,7 @@ aic7770_attach(device_t dev)
*
* First, the aic7770 card specific setup.
*/
- switch (chip & (AHC_EISA|AHC_VL)) {
+ switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
case AHC_EISA:
{
u_int biosctrl;
@@ -299,8 +303,8 @@ aic7770_attach(device_t dev)
*/
{
char *id_string;
- u_int8_t sblkctl;
- u_int8_t sblkctl_orig;
+ uint8_t sblkctl;
+ uint8_t sblkctl_orig;
sblkctl_orig = ahc_inb(ahc, SBLKCTL);
sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
@@ -322,7 +326,7 @@ aic7770_attach(device_t dev)
/* Setup the FIFO threshold and the bus off time */
{
- u_int8_t hostconf = ahc_inb(ahc, HOSTCONF);
+ uint8_t hostconf = ahc_inb(ahc, HOSTCONF);
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
}
@@ -366,8 +370,8 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
{
struct seeprom_descriptor sd;
struct seeprom_config sc;
- u_int16_t checksum = 0;
- u_int8_t scsi_conf;
+ uint16_t checksum = 0;
+ uint8_t scsi_conf;
int have_seeprom;
sd.sd_tag = ahc->tag;
@@ -386,7 +390,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
if (bootverbose)
printf("%s: Reading SEEPROM...", ahc_name(ahc));
have_seeprom = read_seeprom(&sd,
- (u_int16_t *)&sc,
+ (uint16_t *)&sc,
/*start_addr*/0,
sizeof(sc)/2);
@@ -394,7 +398,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
/* Check checksum */
int i;
int maxaddr = (sizeof(sc)/2) - 1;
- u_int16_t *scarray = (u_int16_t *)&sc;
+ uint16_t *scarray = (uint16_t *)&sc;
for (i = 0; i < maxaddr; i++)
checksum = checksum + scarray[i];
@@ -418,11 +422,11 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
*/
int i;
int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
- u_int16_t discenable;
+ uint16_t discenable;
discenable = 0;
for (i = 0; i < max_targ; i++){
- u_int8_t target_settings;
+ uint8_t target_settings;
target_settings = (sc.device_flags[i] & CFXFER) << 4;
if (sc.device_flags[i] & CFSYNCH)
target_settings |= SOFS;
diff --git a/sys/dev/aic7xxx/ahc_pci.c b/sys/dev/aic7xxx/ahc_pci.c
index d457f6c..4a22f3a 100644
--- a/sys/dev/aic7xxx/ahc_pci.c
+++ b/sys/dev/aic7xxx/ahc_pci.c
@@ -15,12 +15,8 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
- * Where this Software is combined with software released under the terms of
- * the GNU Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -68,15 +64,15 @@
#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */
#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */
-static __inline u_int64_t
+static __inline uint64_t
ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
{
- u_int64_t id;
+ uint64_t id;
id = subvendor
| (subdevice << 16)
- | ((u_int64_t)vendor << 32)
- | ((u_int64_t)device << 48);
+ | ((uint64_t)vendor << 32)
+ | ((uint64_t)device << 48);
return (id);
}
@@ -101,6 +97,7 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#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
@@ -122,6 +119,7 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AHA_3944AU 0x7895900478949004ull
#define ID_AIC7890 0x001F9005000F9005ull
+#define ID_AAA_131U2 0x0013900500039005ull
#define ID_AHA_2930U2 0x0011900501819005ull
#define ID_AHA_2940U2B 0x00109005A1009005ull
#define ID_AHA_2940U2_OEM 0x0010900521809005ull
@@ -146,10 +144,9 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull
#define ID_AIC7810 0x1078900400000000ull
-#define ID_AIC7815 0x1578900400000000ull
+#define ID_AIC7815 0x7815900400000000ull
-typedef int (ahc_device_setup_t)(device_t, char *, ahc_chip *,
- ahc_feature *, ahc_flag *);
+typedef int (ahc_device_setup_t)(device_t, struct ahc_probe_config *);
static ahc_device_setup_t ahc_aic7850_setup;
static ahc_device_setup_t ahc_aic7855_setup;
@@ -157,6 +154,7 @@ static ahc_device_setup_t ahc_aic7859_setup;
static ahc_device_setup_t ahc_aic7860_setup;
static ahc_device_setup_t ahc_aic7870_setup;
static ahc_device_setup_t ahc_aha394X_setup;
+static ahc_device_setup_t ahc_aha494X_setup;
static ahc_device_setup_t ahc_aha398X_setup;
static ahc_device_setup_t ahc_aic7880_setup;
static ahc_device_setup_t ahc_2940Pro_setup;
@@ -169,11 +167,12 @@ static ahc_device_setup_t ahc_aic7896_setup;
static ahc_device_setup_t ahc_aic7899_setup;
static ahc_device_setup_t ahc_raid_setup;
static ahc_device_setup_t ahc_aha394XX_setup;
+static ahc_device_setup_t ahc_aha494XX_setup;
static ahc_device_setup_t ahc_aha398XX_setup;
struct ahc_pci_identity {
- u_int64_t full_id;
- u_int64_t id_mask;
+ uint64_t full_id;
+ uint64_t id_mask;
char *name;
ahc_device_setup_t *setup;
};
@@ -244,6 +243,12 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
"Adaptec 3944 SCSI adapter",
ahc_aha394X_setup
},
+ {
+ ID_AHA_4944,
+ ID_ALL_MASK,
+ "Adaptec 4944 SCSI adapter",
+ ahc_aha494X_setup
+ },
/* aic7880 based controllers */
{
ID_AHA_2940U & ID_DEV_VENDOR_MASK,
@@ -334,6 +339,12 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
"Adaptec 2950 Ultra2 SCSI adapter",
ahc_aic7890_setup
},
+ {
+ ID_AAA_131U2,
+ ID_ALL_MASK,
+ "Adaptec AAA-131 Ultra2 RAID adapter",
+ ahc_aic7890_setup
+ },
/* aic7892 based controllers */
{
ID_AHA_29160,
@@ -519,6 +530,11 @@ static const int ahc_num_pci_devs =
#define AHC_398X_SLOT_CHANNEL_B 8
#define AHC_398X_SLOT_CHANNEL_C 12
+#define AHC_494X_SLOT_CHANNEL_A 4
+#define AHC_494X_SLOT_CHANNEL_B 5
+#define AHC_494X_SLOT_CHANNEL_C 6
+#define AHC_494X_SLOT_CHANNEL_D 7
+
#define DEVCONFIG 0x40
#define SCBSIZE32 0x00010000ul /* aic789X only */
#define MPORTMODE 0x00000400ul /* aic7870 only */
@@ -539,9 +555,10 @@ static const int ahc_num_pci_devs =
static struct ahc_pci_identity *ahc_find_pci_device(device_t dev);
static int ahc_ext_scbram_present(struct ahc_softc *ahc);
-static void ahc_ext_scbram_config(struct ahc_softc *ahc, int enable,
- int pcheck, int fast);
+static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
+ int pcheck, int fast, int large);
static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
+static int verify_cksum(struct seeprom_config *sc);
static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
static void configure_termination(struct ahc_softc *ahc,
struct seeprom_descriptor *sd,
@@ -564,8 +581,8 @@ static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
static int acquire_seeprom(struct ahc_softc *ahc,
struct seeprom_descriptor *sd);
static void release_seeprom(struct seeprom_descriptor *sd);
-static void write_brdctl(struct ahc_softc *ahc, u_int8_t value);
-static u_int8_t read_brdctl(struct ahc_softc *ahc);
+static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
+static uint8_t read_brdctl(struct ahc_softc *ahc);
static struct ahc_softc *first_398X;
@@ -595,7 +612,7 @@ DRIVER_MODULE(ahc, pci, ahc_pci_driver, ahc_devclass, 0, 0);
static struct ahc_pci_identity *
ahc_find_pci_device(device_t dev)
{
- u_int64_t full_id;
+ uint64_t full_id;
struct ahc_pci_identity *entry;
u_int i;
@@ -628,30 +645,32 @@ ahc_pci_probe(device_t dev)
static int
ahc_pci_attach(device_t dev)
{
+ struct ahc_probe_config probe_config;
bus_dma_tag_t parent_dmat;
struct ahc_pci_identity *entry;
struct resource *regs;
struct ahc_softc *ahc;
- u_int command;
struct scb_data *shared_scb_data;
- ahc_chip ahc_t = AHC_NONE;
- ahc_feature ahc_fe = AHC_FENONE;
- ahc_flag ahc_f = AHC_FNONE;
+ u_int command;
int regs_type;
int regs_id;
u_int our_id = 0;
u_int sxfrctl1;
u_int scsiseq;
+ u_int dscommand0;
int error;
int zero;
- char channel;
+ uint8_t sblkctl;
shared_scb_data = NULL;
command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1);
entry = ahc_find_pci_device(dev);
if (entry == NULL)
return (ENXIO);
- error = entry->setup(dev, &channel, &ahc_t, &ahc_fe, &ahc_f);
+ ahc_init_probe_config(&probe_config);
+ error = entry->setup(dev, &probe_config);
+ probe_config.chip |= AHC_PCI;
+ probe_config.description = entry->name;
if (error != 0)
return (error);
@@ -700,19 +719,16 @@ ahc_pci_attach(device_t dev)
}
/* On all PCI adapters, we allow SCB paging */
- ahc_f |= AHC_PAGESCBS;
+ probe_config.flags |= AHC_PAGESCBS;
if ((ahc = ahc_alloc(dev, regs, regs_type, regs_id, parent_dmat,
- ahc_t|AHC_PCI, ahc_fe, ahc_f,
- shared_scb_data)) == NULL)
+ &probe_config, shared_scb_data)) == NULL)
return (ENOMEM);
- ahc->channel = channel;
-
/* Store our PCI bus information for use in our PCI error handler */
ahc->device = dev;
/* Remeber how the card was setup in case there is no SEEPROM */
- ahc_outb(ahc, HCNTRL, ahc->pause);
+ pause_sequencer(ahc);
if ((ahc->features & AHC_ULTRA2) != 0)
our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
else
@@ -752,70 +768,62 @@ ahc_pci_attach(device_t dev)
ahc->irq_res_type = SYS_RES_IRQ;
- /*
- * Do aic7880/aic7870/aic7860/aic7850 specific initialization
- */
- {
- u_int8_t sblkctl;
- u_int dscommand0;
+ dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+ dscommand0 |= MPARCKEN;
+ if ((ahc->features & AHC_ULTRA2) != 0) {
- dscommand0 = ahc_inb(ahc, DSCOMMAND0);
- dscommand0 |= MPARCKEN;
- if ((ahc->features & AHC_ULTRA2) != 0) {
+ /*
+ * DPARCKEN doesn't work correctly on
+ * some MBs so don't use it.
+ */
+ dscommand0 &= ~DPARCKEN;
+ dscommand0 |= CACHETHEN|USCBSIZE32;
+ }
- /*
- * DPARCKEN doesn't work correctly on
- * some MBs so don't use it.
- */
- dscommand0 &= ~(USCBSIZE32|DPARCKEN);
- dscommand0 |= CACHETHEN;
- }
+ ahc_outb(ahc, DSCOMMAND0, dscommand0);
- ahc_outb(ahc, DSCOMMAND0, dscommand0);
+ /* See if we have a SEEPROM and perform auto-term */
+ check_extport(ahc, &sxfrctl1);
- /* See if we have an SEEPROM and perform auto-term */
- check_extport(ahc, &sxfrctl1);
+ /*
+ * Take the LED out of diagnostic mode
+ */
+ sblkctl = ahc_inb(ahc, SBLKCTL);
+ ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON)));
- /*
- * Take the LED out of diagnostic mode
- */
- sblkctl = ahc_inb(ahc, SBLKCTL);
- ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON)));
+ /*
+ * I don't know where this is set in the SEEPROM or by the
+ * BIOS, so we default to 100% on Ultra or slower controllers
+ * and 75% on ULTRA2 controllers.
+ */
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75);
+ } else {
+ ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
+ }
+ if (ahc->flags & AHC_USEDEFAULTS) {
/*
- * I don't know where this is set in the SEEPROM or by the
- * BIOS, so we default to 100% on Ultra or slower controllers
- * and 75% on ULTRA2 controllers.
+ * PCI Adapter default setup
+ * Should only be used if the adapter does not have
+ * an SEEPROM.
*/
- if ((ahc->features & AHC_ULTRA2) != 0) {
- ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75);
+ /* See if someone else set us up already */
+ if (scsiseq != 0) {
+ printf("%s: Using left over BIOS settings\n",
+ ahc_name(ahc));
+ ahc->flags &= ~AHC_USEDEFAULTS;
} else {
- ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
- }
-
- if (ahc->flags & AHC_USEDEFAULTS) {
/*
- * PCI Adapter default setup
- * Should only be used if the adapter does not have
- * an SEEPROM.
+ * Assume only one connector and always turn
+ * on termination.
*/
- /* See if someone else set us up already */
- if (scsiseq != 0) {
- printf("%s: Using left over BIOS settings\n",
- ahc_name(ahc));
- ahc->flags &= ~AHC_USEDEFAULTS;
- } else {
- /*
- * Assume only one connector and always turn
- * on termination.
- */
- our_id = 0x07;
- sxfrctl1 = STPWEN;
- }
- ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
-
- ahc->our_id = our_id;
+ our_id = 0x07;
+ sxfrctl1 = STPWEN;
}
+ ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
+
+ ahc->our_id = our_id;
}
/*
@@ -825,7 +833,6 @@ ahc_pci_attach(device_t dev)
*/
ahc_probe_ext_scbram(ahc);
-
printf("%s: %s ", ahc_name(ahc),
ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]);
@@ -861,7 +868,7 @@ ahc_ext_scbram_present(struct ahc_softc *ahc)
{
int ramps;
int single_user;
- u_int32_t devconfig;
+ uint32_t devconfig;
devconfig = pci_read_config(ahc->device, DEVCONFIG, /*bytes*/4);
single_user = (devconfig & MPORTMODE) != 0;
@@ -882,9 +889,10 @@ ahc_ext_scbram_present(struct ahc_softc *ahc)
* Enable external scbram.
*/
static void
-ahc_ext_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast)
+ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck,
+ int fast, int large)
{
- u_int32_t devconfig;
+ uint32_t devconfig;
if (ahc->features & AHC_MULTI_FUNC) {
/*
@@ -903,6 +911,10 @@ ahc_ext_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast)
dscommand0 &= ~INTSCBRAMSEL;
else
dscommand0 |= INTSCBRAMSEL;
+ if (large)
+ dscommand0 |= USCBSIZE32;
+ else
+ dscommand0 &= ~USCBSIZE32;
ahc_outb(ahc, DSCOMMAND0, dscommand0);
} else {
if (fast)
@@ -913,6 +925,10 @@ ahc_ext_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast)
devconfig &= ~SCBRAMSEL;
else
devconfig |= SCBRAMSEL;
+ if (large)
+ devconfig &= ~SCBSIZE32;
+ else
+ devconfig |= SCBSIZE32;
}
if (pcheck)
devconfig |= EXTSCBPEN;
@@ -935,17 +951,21 @@ ahc_probe_ext_scbram(struct ahc_softc *ahc)
int enable;
int pcheck;
int fast;
+ int large;
+ enable = FALSE;
+ pcheck = FALSE;
+ fast = FALSE;
+ large = FALSE;
+ num_scbs = 0;
+
if (ahc_ext_scbram_present(ahc) == 0)
return;
/*
* Probe for the best parameters to use.
*/
- enable = FALSE;
- pcheck = FALSE;
- fast = FALSE;
- ahc_ext_scbram_config(ahc, /*enable*/TRUE, pcheck, fast);
+ ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large);
num_scbs = ahc_probe_scbs(ahc);
if (num_scbs == 0) {
/* The SRAM wasn't really present. */
@@ -963,7 +983,7 @@ ahc_probe_ext_scbram(struct ahc_softc *ahc)
ahc_outb(ahc, CLRINT, CLRBRKADRINT);
/* Now see if we can do parity */
- ahc_ext_scbram_config(ahc, enable, /*pcheck*/TRUE, fast);
+ ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large);
num_scbs = ahc_probe_scbs(ahc);
if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
|| (ahc_inb(ahc, ERROR) & MPARERR) == 0)
@@ -974,13 +994,32 @@ ahc_probe_ext_scbram(struct ahc_softc *ahc)
ahc_outb(ahc, CLRINT, CLRBRKADRINT);
/* Now see if we can do fast timing */
- ahc_ext_scbram_config(ahc, enable, pcheck, /*fast*/TRUE);
+ ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large);
test_num_scbs = ahc_probe_scbs(ahc);
if (test_num_scbs == num_scbs
&& ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
|| (ahc_inb(ahc, ERROR) & MPARERR) == 0))
fast = TRUE;
+ /*
+ * See if we can use large SCBs and still maintain
+ * the same overall count of SCBs.
+ */
+ if ((ahc->features & AHC_LARGE_SCBS) != 0) {
+ ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE);
+ test_num_scbs = ahc_probe_scbs(ahc);
+ if (test_num_scbs >= num_scbs) {
+ large = TRUE;
+ num_scbs = test_num_scbs;
+ }
+ if (num_scbs >= 64)
+ /*
+ * We have enough space to move the "busy targets
+ * table" into SCB space and make it qualify all
+ * the way to the lun level.
+ */
+ ahc->flags |= AHC_SCB_BTT;
+ }
done:
/*
* Disable parity error reporting until we
@@ -996,7 +1035,29 @@ done:
pcheck ? ", parity checking enabled" : "");
}
- ahc_ext_scbram_config(ahc, enable, pcheck, fast);
+ ahc_scbram_config(ahc, enable, pcheck, fast, large);
+}
+
+static int
+verify_cksum(struct seeprom_config *sc)
+{
+ int i;
+ int maxaddr;
+ uint32_t checksum;
+ uint16_t *scarray;
+
+ maxaddr = (sizeof(*sc)/2) - 1;
+ checksum = 0;
+ scarray = (uint16_t *)sc;
+
+ for (i = 0; i < maxaddr; i++)
+ checksum = checksum + scarray[i];
+ if (checksum == 0
+ || (checksum & 0xFFFF) != sc->checksum) {
+ return (0);
+ } else {
+ return(1);
+ }
}
/*
@@ -1048,41 +1109,52 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
start_addr = 32 * (ahc->channel - 'A');
- have_seeprom = read_seeprom(&sd, (u_int16_t *)&sc,
+ have_seeprom = read_seeprom(&sd, (uint16_t *)&sc,
start_addr, sizeof(sc)/2);
- if (have_seeprom) {
- /* Check checksum */
- int i;
- int maxaddr;
- u_int32_t checksum;
- u_int16_t *scarray;
-
- maxaddr = (sizeof(sc)/2) - 1;
- checksum = 0;
- scarray = (u_int16_t *)&sc;
-
- for (i = 0; i < maxaddr; i++)
- checksum = checksum + scarray[i];
- if (checksum == 0
- || (checksum & 0xFFFF) != sc.checksum) {
- if (bootverbose && sd.sd_chip == C56_66)
+ if (have_seeprom)
+ have_seeprom = verify_cksum(&sc);
+
+ if (have_seeprom != 0 || sd.sd_chip == C56_66) {
+ if (bootverbose) {
+ if (have_seeprom == 0)
printf ("checksum error\n");
- have_seeprom = 0;
- } else {
- if (bootverbose)
- printf("done.\n");
- break;
+ else
+ printf ("done.\n");
}
- }
-
- if (sd.sd_chip == C56_66)
break;
+ }
sd.sd_chip = C56_66;
}
}
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.
+ */
+ ahc_outb(ahc, SCBPTR, 2);
+ if (ahc_inb(ahc, SCB_CONTROL) == 'A'
+ && ahc_inb(ahc, SCB_CONTROL + 1) == 'D'
+ && ahc_inb(ahc, SCB_CONTROL + 2) == 'P'
+ && ahc_inb(ahc, SCB_CONTROL + 3) == 'T') {
+ uint8_t *sc_bytes;
+ int i;
+
+ printf("Got Here!\n");
+ 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_CONTROL + 4);
+ have_seeprom = verify_cksum(&sc);
+ if (have_seeprom)
+ printf("And it even worked!\n");
+ }
+ }
+
+ if (!have_seeprom) {
if (bootverbose)
printf("%s: No SEEPROM available.\n", ahc_name(ahc));
ahc->flags |= AHC_USEDEFAULTS;
@@ -1093,8 +1165,8 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
*/
int i;
int max_targ = sc.max_targets & CFMAXTARG;
- u_int16_t discenable;
- u_int16_t ultraenb;
+ uint16_t discenable;
+ uint16_t ultraenb;
discenable = 0;
ultraenb = 0;
@@ -1113,7 +1185,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
for (i = 0; i < max_targ; i++) {
u_int scsirate;
- u_int16_t target_mask;
+ uint16_t target_mask;
target_mask = 0x01 << i;
if (sc.device_flags[i] & CFDISC)
@@ -1139,6 +1211,11 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
offset = 0;
ahc_outb(ahc, TARG_OFFSET + i, offset);
+ /*
+ * The ultra enable bits contain the
+ * high bit of the ultra2 sync rate
+ * field.
+ */
scsirate = (sc.device_flags[i] & CFXFER)
| ((ultraenb & target_mask)
? 0x8 : 0x0);
@@ -1170,6 +1247,19 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
/* Treat us as a non-ultra card */
ultraenb = 0;
}
+
+ if (sc.signature == CFSIGNATURE) {
+ uint32_t devconfig;
+
+ /* Honor the STPWLEVEL settings */
+ devconfig = pci_read_config(ahc->device, DEVCONFIG,
+ /*bytes*/4);
+ devconfig &= ~STPWLEVEL;
+ if ((sc.bios_control & CFSTPWLEVEL) != 0)
+ devconfig |= STPWLEVEL;
+ pci_write_config(ahc->device, DEVCONFIG,
+ devconfig, /*bytes*/4);
+ }
/* Set SCSICONF info */
ahc_outb(ahc, SCSICONF, scsi_conf);
ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
@@ -1214,7 +1304,7 @@ configure_termination(struct ahc_softc *ahc,
u_int adapter_control,
u_int *sxfrctl1)
{
- u_int8_t brddat;
+ uint8_t brddat;
brddat = 0;
@@ -1255,15 +1345,16 @@ configure_termination(struct ahc_softc *ahc,
if (bootverbose)
printf("%s: Manual SE Termination\n",
ahc_name(ahc));
- enableSEC_low = (adapter_control & CFSTERM);
- enableSEC_high = (adapter_control & CFWSTERM);
+ enableSEC_low = (adapter_control & CFSELOWTERM);
+ enableSEC_high =
+ (adapter_control & CFSEHIGHTERM);
}
if ((adapter_control & CFAUTOTERM) == 0) {
if (bootverbose)
printf("%s: Manual LVD Termination\n",
ahc_name(ahc));
- enablePRI_low = enablePRI_high =
- (adapter_control & CFLVDSTERM);
+ enablePRI_low = (adapter_control & CFSTERM);
+ enablePRI_high = (adapter_control & CFWSTERM);
}
/* Make the table calculations below happy */
internal50_present = 0;
@@ -1424,7 +1515,7 @@ ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
int *enableSEC_high, int *enablePRI_low,
int *enablePRI_high, int *eeprom_present)
{
- u_int8_t brdctl;
+ uint8_t brdctl;
/*
* BRDDAT7 = Eeprom
@@ -1446,7 +1537,7 @@ aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
int *internal68_present, int *externalcable_present,
int *eeprom_present)
{
- u_int8_t brdctl;
+ uint8_t brdctl;
/*
* First read the status of our cables.
@@ -1486,7 +1577,7 @@ static void
aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
int *externalcable_present, int *eeprom_present)
{
- u_int8_t brdctl;
+ uint8_t brdctl;
ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
ahc_outb(ahc, BRDCTL, 0);
@@ -1533,9 +1624,9 @@ release_seeprom(struct seeprom_descriptor *sd)
}
static void
-write_brdctl(struct ahc_softc *ahc, u_int8_t value)
+write_brdctl(struct ahc_softc *ahc, uint8_t value)
{
- u_int8_t brdctl;
+ uint8_t brdctl;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
brdctl = BRDSTB;
@@ -1564,12 +1655,12 @@ write_brdctl(struct ahc_softc *ahc, u_int8_t value)
ahc_outb(ahc, BRDCTL, brdctl);
}
-static u_int8_t
+static uint8_t
read_brdctl(ahc)
struct ahc_softc *ahc;
{
- u_int8_t brdctl;
- u_int8_t value;
+ uint8_t brdctl;
+ uint8_t value;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
brdctl = BRDRW;
@@ -1597,7 +1688,7 @@ read_brdctl(ahc)
void
ahc_pci_intr(struct ahc_softc *ahc)
{
- u_int8_t status1;
+ uint8_t status1;
status1 = pci_read_config(ahc->device, PCIR_STATUS + 1, /*bytes*/1);
@@ -1633,236 +1724,264 @@ ahc_pci_intr(struct ahc_softc *ahc)
}
static int
-ahc_aic7850_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7850_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7850;
- *features = AHC_AIC7850_FE;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7850;
+ probe_config->features = AHC_AIC7850_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_aic7855_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7855_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7855;
- *features = AHC_AIC7855_FE;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7855;
+ probe_config->features = AHC_AIC7855_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_aic7859_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7859_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7859;
- *features = AHC_AIC7859_FE;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7859;
+ probe_config->features = AHC_AIC7859_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_aic7860_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7860_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7860;
- *features = AHC_AIC7860_FE;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7860;
+ probe_config->features = AHC_AIC7860_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_aic7870_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7870_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7870;
- *features = AHC_AIC7870_FE;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7870;
+ probe_config->features = AHC_AIC7870_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_aha394X_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha394X_setup(device_t dev, struct ahc_probe_config *probe_config)
{
int error;
- error = ahc_aic7870_setup(dev, channel, chip, features, flags);
+ error = ahc_aic7870_setup(dev, probe_config);
if (error == 0)
- error = ahc_aha394XX_setup(dev, channel, chip, features, flags);
+ error = ahc_aha394XX_setup(dev, probe_config);
return (error);
}
static int
-ahc_aha398X_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha398X_setup(device_t dev, struct ahc_probe_config *probe_config)
{
int error;
- error = ahc_aic7870_setup(dev, channel, chip, features, flags);
+ error = ahc_aic7870_setup(dev, probe_config);
if (error == 0)
- error = ahc_aha398XX_setup(dev, channel, chip, features, flags);
+ error = ahc_aha398XX_setup(dev, probe_config);
return (error);
}
static int
-ahc_aic7880_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha494X_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7880;
- *features = AHC_AIC7880_FE;
+ int error;
+
+ error = ahc_aic7870_setup(dev, probe_config);
+ if (error == 0)
+ error = ahc_aha494XX_setup(dev, probe_config);
+ return (error);
+}
+
+static int
+ahc_aic7880_setup(device_t dev, struct ahc_probe_config *probe_config)
+{
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7880;
+ probe_config->features = AHC_AIC7880_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
return (0);
}
static int
-ahc_2940Pro_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_2940Pro_setup(device_t dev, struct ahc_probe_config *probe_config)
{
int error;
- *flags |= AHC_INT50_SPEEDFLEX;
- error = ahc_aic7880_setup(dev, channel, chip, features, flags);
+ probe_config->flags |= AHC_INT50_SPEEDFLEX;
+ error = ahc_aic7880_setup(dev, probe_config);
return (0);
}
static int
-ahc_aha394XU_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha394XU_setup(device_t dev, struct ahc_probe_config *probe_config)
{
int error;
- error = ahc_aic7880_setup(dev, channel, chip, features, flags);
+ error = ahc_aic7880_setup(dev, probe_config);
if (error == 0)
- error = ahc_aha394XX_setup(dev, channel, chip, features, flags);
+ error = ahc_aha394XX_setup(dev, probe_config);
return (error);
}
static int
-ahc_aha398XU_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha398XU_setup(device_t dev, struct ahc_probe_config *probe_config)
{
int error;
- error = ahc_aic7880_setup(dev, channel, chip, features, flags);
+ error = ahc_aic7880_setup(dev, probe_config);
if (error == 0)
- error = ahc_aha398XX_setup(dev, channel, chip, features, flags);
+ error = ahc_aha398XX_setup(dev, probe_config);
return (error);
}
static int
-ahc_aic7890_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7890_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7890;
- *features = AHC_AIC7890_FE;
- *flags |= AHC_NEWEEPROM_FMT;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7890;
+ probe_config->features = AHC_AIC7890_FE;
+ probe_config->flags |= AHC_NEWEEPROM_FMT;
+ if (pci_get_revid(dev) == 0)
+ probe_config->bugs |= AHC_AUTOFLUSH_BUG;
return (0);
}
static int
-ahc_aic7892_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7892_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = 'A';
- *chip = AHC_AIC7892;
- *features = AHC_AIC7892_FE;
- *flags |= AHC_NEWEEPROM_FMT;
+ probe_config->channel = 'A';
+ probe_config->chip = AHC_AIC7892;
+ probe_config->features = AHC_AIC7892_FE;
+ probe_config->flags |= AHC_NEWEEPROM_FMT;
return (0);
}
static int
-ahc_aic7895_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7895_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- u_int32_t devconfig;
+ uint32_t devconfig;
- *channel = pci_get_function(dev) == 1 ? 'B' : 'A';
- *chip = AHC_AIC7895;
+ probe_config->channel = pci_get_function(dev) == 1 ? 'B' : 'A';
+ probe_config->chip = AHC_AIC7895;
/* The 'C' revision of the aic7895 has a few additional features */
if (pci_get_revid(dev) >= 4)
- *features = AHC_AIC7895C_FE;
+ probe_config->features = AHC_AIC7895C_FE;
else
- *features = AHC_AIC7895_FE;
- *flags |= AHC_NEWEEPROM_FMT;
+ probe_config->features = AHC_AIC7895_FE;
+ probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
+ probe_config->flags |= AHC_NEWEEPROM_FMT;
devconfig = pci_read_config(dev, DEVCONFIG, /*bytes*/4);
- devconfig &= ~SCBSIZE32;
+ devconfig |= SCBSIZE32;
pci_write_config(dev, DEVCONFIG, devconfig, /*bytes*/4);
return (0);
}
static int
-ahc_aic7896_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7896_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = pci_get_function(dev) == 1 ? 'B' : 'A';
- *chip = AHC_AIC7896;
- *features = AHC_AIC7896_FE;
- *flags |= AHC_NEWEEPROM_FMT;
+ probe_config->channel = pci_get_function(dev) == 1 ? 'B' : 'A';
+ probe_config->chip = AHC_AIC7896;
+ probe_config->features = AHC_AIC7896_FE;
+ probe_config->flags |= AHC_NEWEEPROM_FMT;
return (0);
}
static int
-ahc_aic7899_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aic7899_setup(device_t dev, struct ahc_probe_config *probe_config)
{
- *channel = pci_get_function(dev) == 1 ? 'B' : 'A';
- *chip = AHC_AIC7899;
- *features = AHC_AIC7899_FE;
- *flags |= AHC_NEWEEPROM_FMT;
+ probe_config->channel = pci_get_function(dev) == 1 ? 'B' : 'A';
+ probe_config->chip = AHC_AIC7899;
+ probe_config->features = AHC_AIC7899_FE;
+ probe_config->flags |= AHC_NEWEEPROM_FMT;
return (0);
}
static int
-ahc_raid_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_raid_setup(device_t dev, struct ahc_probe_config *probe_config)
{
printf("RAID functionality unsupported\n");
return (ENXIO);
}
static int
-ahc_aha394XX_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha394XX_setup(device_t dev, struct ahc_probe_config *probe_config)
{
switch (pci_get_slot(dev)) {
case AHC_394X_SLOT_CHANNEL_A:
- *channel = 'A';
+ probe_config->channel = 'A';
break;
case AHC_394X_SLOT_CHANNEL_B:
- *channel = 'B';
+ probe_config->channel = 'B';
break;
default:
printf("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
pci_get_slot(dev));
- *channel = 'A';
+ probe_config->channel = 'A';
}
return (0);
}
static int
-ahc_aha398XX_setup(device_t dev, char *channel, ahc_chip *chip,
- ahc_feature *features, ahc_flag *flags)
+ahc_aha398XX_setup(device_t dev, struct ahc_probe_config *probe_config)
{
switch (pci_get_slot(dev)) {
case AHC_398X_SLOT_CHANNEL_A:
- *channel = 'A';
+ probe_config->channel = 'A';
break;
case AHC_398X_SLOT_CHANNEL_B:
- *channel = 'B';
+ probe_config->channel = 'B';
break;
case AHC_398X_SLOT_CHANNEL_C:
- *channel = 'C';
+ probe_config->channel = 'C';
+ break;
+ default:
+ printf("adapter at unexpected slot %d\n"
+ "unable to map to a channel\n",
+ pci_get_slot(dev));
+ probe_config->channel = 'A';
+ break;
+ }
+ probe_config->flags |= AHC_LARGE_SEEPROM;
+ return (0);
+}
+
+static int
+ahc_aha494XX_setup(device_t dev, struct ahc_probe_config *probe_config)
+{
+ switch (pci_get_slot(dev)) {
+ case AHC_494X_SLOT_CHANNEL_A:
+ probe_config->channel = 'A';
+ break;
+ case AHC_494X_SLOT_CHANNEL_B:
+ probe_config->channel = 'B';
+ break;
+ case AHC_494X_SLOT_CHANNEL_C:
+ probe_config->channel = 'C';
+ break;
+ case AHC_494X_SLOT_CHANNEL_D:
+ probe_config->channel = 'D';
break;
default:
printf("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
pci_get_slot(dev));
- *channel = 'A';
+ probe_config->channel = 'A';
}
- *flags |= AHC_LARGE_SEEPROM;
+ probe_config->flags |= AHC_LARGE_SEEPROM;
return (0);
}
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c
index e89434a..3859c19 100644
--- a/sys/dev/aic7xxx/aic7xxx.c
+++ b/sys/dev/aic7xxx/aic7xxx.c
@@ -18,7 +18,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -110,6 +110,7 @@
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <machine/clock.h>
+#include <machine/endian.h>
#include <sys/rman.h>
#include <vm/vm.h>
@@ -117,7 +118,7 @@
#include <vm/pmap.h>
#include <dev/aic7xxx/aic7xxx.h>
-#include <dev/aic7xxx/sequencer.h>
+#include <dev/aic7xxx/aicasm_insformat.h>
#include <aic7xxx_reg.h>
#include <aic7xxx_seq.h>
@@ -142,24 +143,36 @@
(((sim) == ahc->sim_b) ? ahc->our_id_b : ahc->our_id)
#define SIM_PATH(ahc, sim) \
(((sim) == ahc->sim_b) ? ahc->path_b : ahc->path)
-#define SCB_IS_SCSIBUS_B(scb) \
- (((scb)->hscb->tcl & SELBUSB) != 0)
-#define SCB_TARGET(scb) \
- (((scb)->hscb->tcl & TID) >> 4)
-#define SCB_CHANNEL(scb) \
- (SCB_IS_SCSIBUS_B(scb) ? 'B' : 'A')
-#define SCB_LUN(scb) \
- ((scb)->hscb->tcl & LID)
-#define SCB_TARGET_OFFSET(scb) \
- (SCB_TARGET(scb) + (SCB_IS_SCSIBUS_B(scb) ? 8 : 0))
-#define SCB_TARGET_MASK(scb) \
- (0x01 << (SCB_TARGET_OFFSET(scb)))
-#define TCL_CHANNEL(ahc, tcl) \
- ((((ahc)->features & AHC_TWIN) && ((tcl) & SELBUSB)) ? 'B' : 'A')
-#define TCL_SCSI_ID(ahc, tcl) \
- (TCL_CHANNEL((ahc), (tcl)) == 'B' ? (ahc)->our_id_b : (ahc)->our_id)
-#define TCL_TARGET(tcl) (((tcl) & TID) >> TCL_TARGET_SHIFT)
-#define TCL_LUN(tcl) ((tcl) & LID)
+#define SCSIID_TARGET(ahc, scsiid) \
+ (((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \
+ >> TID_SHIFT)
+#define SCSIID_OUR_ID(scsiid) \
+ ((scsiid) & OID)
+#define SCSIID_CHANNEL(ahc, scsiid) \
+ ((((ahc)->features & AHC_TWIN) != 0) \
+ ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \
+ : 'A')
+#define SCB_IS_SCSIBUS_B(ahc, scb) \
+ (SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B')
+#define SCB_GET_OUR_ID(scb) \
+ SCSIID_OUR_ID((scb)->hscb->scsiid)
+#define SCB_GET_TARGET(ahc, scb) \
+ SCSIID_TARGET((ahc), (scb)->hscb->scsiid)
+#define SCB_GET_CHANNEL(ahc, scb) \
+ SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid)
+#define SCB_GET_LUN(scb) \
+ ((scb)->hscb->lun)
+#define SCB_GET_TARGET_OFFSET(ahc, scb) \
+ (SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0))
+#define SCB_GET_TARGET_MASK(ahc, scb) \
+ (0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb)))
+#define TCL_TARGET_OFFSET(tcl) \
+ ((((tcl) >> 4) & TID) >> 4)
+#define BUILD_TCL(scsiid, lun) \
+ ((lun) | (((scsiid) & TID) >> 4))
+#define BUILD_SCSIID(ahc, sim, target_id, our_id) \
+ ((((target_id) << TID_SHIFT) & TID) | (our_id) \
+ | (SIM_IS_SCSIBUS_B(ahc, sim) ? TWIN_CHNLB : 0))
#define ccb_scb_ptr spriv_ptr0
#define ccb_ahc_ptr spriv_ptr1
@@ -174,10 +187,10 @@ char *ahc_chip_names[] =
"aic7860",
"aic7870",
"aic7880",
- "aic7890/91",
- "aic7892",
"aic7895",
+ "aic7890/91",
"aic7896/97",
+ "aic7892",
"aic7899"
};
@@ -190,9 +203,9 @@ typedef enum {
struct ahc_devinfo {
int our_scsiid;
int target_offset;
- u_int16_t target_mask;
- u_int8_t target;
- u_int8_t lun;
+ uint16_t target_mask;
+ uint8_t target;
+ uint8_t lun;
char channel;
role_t role; /*
* Only guaranteed to be correct if not
@@ -230,7 +243,7 @@ static cam_status
struct tmode_lstate **lstate,
int notfound_failure);
static void ahc_action(struct cam_sim *sim, union ccb *ccb);
-static void ahc_async(void *callback_arg, u_int32_t code,
+static void ahc_async(void *callback_arg, uint32_t code,
struct cam_path *path, void *arg);
static void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
int nsegments, int error);
@@ -249,7 +262,7 @@ static void ahc_fetch_devinfo(struct ahc_softc *ahc,
static void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id,
u_int target, u_int lun, char channel,
role_t role);
-static u_int ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev);
+static u_int ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev);
static void ahc_done(struct ahc_softc *ahc, struct scb *scbp);
static struct tmode_tstate *
ahc_alloc_tstate(struct ahc_softc *ahc,
@@ -296,17 +309,18 @@ static void ahc_dumpseq(struct ahc_softc *ahc);
static void ahc_loadseq(struct ahc_softc *ahc);
static int ahc_check_patch(struct ahc_softc *ahc,
struct patch **start_patch,
- int start_instr, int *skip_addr);
+ u_int start_instr, u_int *skip_addr);
static void ahc_download_instr(struct ahc_softc *ahc,
- int instrptr, u_int8_t *dconsts);
-static int ahc_match_scb(struct scb *scb, int target, char channel,
- int lun, u_int tag, role_t role);
+ u_int instrptr, uint8_t *dconsts);
+static int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
+ int target, char channel, int lun, u_int tag,
+ role_t role);
#ifdef AHC_DEBUG
static void ahc_print_scb(struct scb *scb);
#endif
static int ahc_search_qinfifo(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
- role_t role, u_int32_t status,
+ role_t role, uint32_t status,
ahc_search_action action);
static void ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim,
union ccb *ccb);
@@ -314,7 +328,7 @@ static int ahc_reset_channel(struct ahc_softc *ahc, char channel,
int initiate_reset);
static int ahc_abort_scbs(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag, role_t role,
- u_int32_t status);
+ uint32_t status);
static int ahc_search_disc_list(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
int stop_on_first, int remove,
@@ -325,15 +339,17 @@ static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc);
static void ahc_clear_intstat(struct ahc_softc *ahc);
static void ahc_reset_current_bus(struct ahc_softc *ahc);
static struct ahc_syncrate *
- ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period);
+ ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period,
+ u_int *ppr_options);
static struct ahc_syncrate *
ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
- u_int maxsync);
+ u_int *ppr_options, u_int maxsync);
static u_int ahc_find_period(struct ahc_softc *ahc, u_int scsirate,
u_int maxsync);
static void ahc_validate_offset(struct ahc_softc *ahc,
struct ahc_syncrate *syncrate,
u_int *offset, int wide);
+static void ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width);
static void ahc_update_target_msg_request(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
struct ahc_initiator_tinfo *tinfo,
@@ -345,7 +361,8 @@ static void ahc_set_syncrate(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
struct cam_path *path,
struct ahc_syncrate *syncrate,
- u_int period, u_int offset, u_int type,
+ u_int period, u_int offset,
+ u_int ppr_options, u_int type,
int paused);
static void ahc_set_width(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
@@ -358,7 +375,11 @@ static void ahc_construct_sdtr(struct ahc_softc *ahc,
u_int period, u_int offset);
static void ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width);
+static void ahc_construct_ppr(struct ahc_softc *ahc, u_int period,
+ u_int offset, u_int bus_width,
+ u_int ppr_options);
+static __inline int ahc_check_residual(struct scb *scb);
static void ahc_calc_residual(struct scb *scb);
static void ahc_update_pending_syncrates(struct ahc_softc *ahc);
@@ -373,19 +394,17 @@ static void ahc_queue_lstate_event(struct ahc_softc *ahc,
u_int event_arg);
static void ahc_send_lstate_events(struct ahc_softc *ahc,
struct tmode_lstate *lstate);
-static __inline int sequencer_paused(struct ahc_softc *ahc);
-static __inline void pause_sequencer(struct ahc_softc *ahc);
-static __inline void unpause_sequencer(struct ahc_softc *ahc);
static void restart_sequencer(struct ahc_softc *ahc);
static __inline u_int ahc_index_busy_tcl(struct ahc_softc *ahc,
u_int tcl, int unbusy);
-static __inline void ahc_busy_tcl(struct ahc_softc *ahc, struct scb *scb);
-
static __inline void ahc_freeze_ccb(union ccb* ccb);
static __inline cam_status ahc_ccb_status(union ccb* ccb);
static __inline void ahcsetccbstatus(union ccb* ccb,
cam_status status);
+static void ahc_run_untagged_queues(struct ahc_softc *);
+static void ahc_run_untagged_queue(struct ahc_softc *,
+ struct scb_tailq *);
static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
static void ahc_run_qoutfifo(struct ahc_softc *ahc);
@@ -394,43 +413,27 @@ static __inline struct ahc_initiator_tinfo *
char channel,
u_int our_id, u_int target,
struct tmode_tstate **tstate);
+static __inline struct ahc_dma_seg *
+ ahc_sg_bus_to_virt(struct scb *scb,
+ uint32_t sg_busaddr);
+static __inline uint32_t
+ ahc_sg_virt_to_bus(struct scb *scb,
+ struct ahc_dma_seg *sg);
+static __inline void ahc_queue_scb(struct ahc_softc *ahc,
+ struct scb *scb);
static void ahcfreescb(struct ahc_softc *ahc, struct scb *scb);
static __inline struct scb *ahcgetscb(struct ahc_softc *ahc);
+static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
+static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
-static __inline u_int32_t
+static __inline uint32_t
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
{
return (ahc->scb_data->hscb_busaddr
+ (sizeof(struct hardware_scb) * index));
}
-#define AHC_BUSRESET_DELAY 25 /* Reset delay in us */
-
-static __inline int
-sequencer_paused(struct ahc_softc *ahc)
-{
- return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
-}
-
-static __inline void
-pause_sequencer(struct ahc_softc *ahc)
-{
- ahc_outb(ahc, HCNTRL, ahc->pause);
-
- /*
- * Since the sequencer can disable pausing in a critical section, we
- * must loop until it actually stops.
- */
- while (sequencer_paused(ahc) == 0)
- ;
-}
-
-static __inline void
-unpause_sequencer(struct ahc_softc *ahc)
-{
- if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
- ahc_outb(ahc, HCNTRL, ahc->unpause);
-}
+#define AHC_BUSRESET_DELAY 250 /* Reset delay in us */
/*
* Restart the sequencer program from address zero
@@ -457,8 +460,9 @@ restart_sequencer(struct ahc_softc *ahc)
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
ahc_outb(ahc, SCBPTR, i);
- if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL)
+ if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL) {
ahc_add_curscb_to_free_list(ahc);
+ }
}
ahc_outb(ahc, SEQCTL, FASTMODE|SEQRESET);
unpause_sequencer(ahc);
@@ -468,18 +472,25 @@ static __inline u_int
ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl, int unbusy)
{
u_int scbid;
+ u_int target_offset;
- scbid = ahc->untagged_scbs[tcl];
+ target_offset = TCL_TARGET_OFFSET(tcl);
+ scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset);
if (unbusy)
- ahc->untagged_scbs[tcl] = SCB_LIST_NULL;
+ ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL);
return (scbid);
}
-static __inline void
-ahc_busy_tcl(struct ahc_softc *ahc, struct scb *scb)
+static __inline int
+ahc_check_residual(struct scb *scb)
{
- ahc->untagged_scbs[scb->hscb->tcl] = scb->hscb->tag;
+ struct status_pkt *sp;
+
+ sp = &scb->hscb->shared_data.status;
+ if ((scb->hscb->sgptr & SG_RESID_VALID) != 0)
+ return (1);
+ return (0);
}
static __inline void
@@ -520,6 +531,83 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
return (&(*tstate)->transinfo[remote_id]);
}
+static __inline struct ahc_dma_seg *
+ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
+{
+ int sg_index;
+
+ sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_index++;
+
+ return (&scb->sg_list[sg_index]);
+}
+
+static __inline uint32_t
+ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
+{
+ int sg_index;
+
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_index = sg - &scb->sg_list[1];
+
+ return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
+}
+
+static __inline void
+ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+ ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+ if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+ } else {
+ pause_sequencer(ahc);
+ ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+ unpause_sequencer(ahc);
+ }
+}
+
+static __inline void
+ahc_freeze_untagged_queues(struct ahc_softc *ahc)
+{
+ if ((ahc->features & AHC_SCB_BTT) == 0)
+ ahc->untagged_queue_lock++;
+}
+
+static __inline void
+ahc_release_untagged_queues(struct ahc_softc *ahc)
+{
+ if ((ahc->features & AHC_SCB_BTT) == 0) {
+ ahc->untagged_queue_lock--;
+ if (ahc->untagged_queue_lock == 0)
+ ahc_run_untagged_queues(ahc);
+ }
+}
+
+static void
+ahc_run_untagged_queues(struct ahc_softc *ahc)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);
+}
+
+static void
+ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
+{
+ struct scb *scb;
+
+ if (ahc->untagged_queue_lock != 0)
+ return;
+
+ if ((scb = TAILQ_FIRST(queue)) != NULL
+ && (scb->flags & SCB_ACTIVE) == 0) {
+ scb->flags |= SCB_ACTIVE;
+ ahc_queue_scb(ahc, scb);
+ }
+}
+
static void
ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
{
@@ -529,7 +617,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
/*
* Only advance through the queue if we
- * had the resources to process the command.
+ * have the resources to process the command.
*/
if (ahc_handle_target_cmd(ahc, cmd) != 0)
break;
@@ -585,7 +673,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
* Save off the residual
* if there is one.
*/
- if (scb->hscb->residual_SG_count != 0)
+ if (ahc_check_residual(scb) != 0)
ahc_calc_residual(scb);
else
scb->ccb->csio.resid = 0;
@@ -595,8 +683,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
/*
- * An scb (and hence an scb entry on the board) is put onto the
- * free list.
+ * Return an SCB resource to the free list.
*/
static void
ahcfreescb(struct ahc_softc *ahc, struct scb *scb)
@@ -617,17 +704,13 @@ ahcfreescb(struct ahc_softc *ahc, struct scb *scb)
/* Clean up for the next user */
scb->flags = SCB_FREE;
hscb->control = 0;
- hscb->status = 0;
- SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links);
+ SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
splx(opri);
}
/*
- * Get a free scb, either one already assigned to a hardware slot
- * on the adapter or one that will require an SCB to be paged out before
- * use. If there are none, see if we can allocate a new SCB. Otherwise
- * either return an error or sleep.
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
*/
static __inline struct scb *
ahcgetscb(struct ahc_softc *ahc)
@@ -637,12 +720,12 @@ ahcgetscb(struct ahc_softc *ahc)
opri = splcam();
if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) {
- SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links);
+ SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
} else {
ahcallocscbs(ahc);
scbp = SLIST_FIRST(&ahc->scb_data->free_scbs);
if (scbp != NULL)
- SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links);
+ SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
}
splx(opri);
@@ -663,32 +746,50 @@ ahc_name(struct ahc_softc *ahc)
static void
ahc_print_scb(struct scb *scb)
{
+ int i;
+
struct hardware_scb *hscb = scb->hscb;
- printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%x\n",
- scb,
- hscb->control,
- hscb->tcl,
- hscb->cmdlen,
- hscb->cmdpointer);
- printf(" datlen:%d data:0x%x segs:0x%x segp:0x%x\n",
- hscb->datalen,
- hscb->data,
- hscb->SG_count,
- hscb->SG_pointer);
- printf(" sg_addr:%x sg_len:%d\n",
- scb->sg_list[0].addr,
- scb->sg_list[0].len);
- printf(" cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n",
- hscb->cmdstore[0], hscb->cmdstore[1], hscb->cmdstore[2],
- hscb->cmdstore[3], hscb->cmdstore[4], hscb->cmdstore[5],
- hscb->cmdstore[6], hscb->cmdstore[7], hscb->cmdstore[8],
- hscb->cmdstore[9], hscb->cmdstore[10], hscb->cmdstore[11]);
+ printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+ scb,
+ hscb->control,
+ hscb->scsiid,
+ hscb->lun,
+ hscb->cdb_len);
+ i = 0;
+ printf("Shared Data: %#02x %#02x %#02x %#02x\n",
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++]);
+ printf(" %#02x %#02x %#02x %#02x\n",
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++]);
+ printf(" %#02x %#02x %#02x %#02x\n",
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++],
+ hscb->shared_data.cdb[i++]);
+ printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
+ hscb->dataptr,
+ hscb->datacnt,
+ hscb->sgptr,
+ hscb->tag);
+ if (scb->sg_count > 0) {
+ for (i = 0; i < scb->sg_count; i++) {
+ printf("sg[%d] - Addr 0x%x : Length %d\n",
+ i,
+ scb->sg_list[i].addr,
+ scb->sg_list[i].len);
+ }
+ }
}
#endif
static struct {
- u_int8_t errno;
+ uint8_t errno;
char *errmesg;
} hard_error[] = {
{ ILLHADDR, "Illegal Host Access" },
@@ -703,8 +804,8 @@ static struct {
static const int num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
static struct {
- u_int8_t phase;
- u_int8_t mesg_out; /* Message response to parity errors */
+ uint8_t phase;
+ uint8_t mesg_out; /* Message response to parity errors */
char *phasemsg;
} phase_table[] = {
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
@@ -716,7 +817,8 @@ static struct {
{ P_BUSFREE, MSG_NOOP, "while idle" },
{ 0, MSG_NOOP, "in unknown phase" }
};
-static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1;
+static const u_int num_phases =
+ (sizeof(phase_table)/sizeof(phase_table[0])) - 1;
/*
* Valid SCSIRATE values. (p. 3-17)
@@ -746,22 +848,35 @@ static struct ahc_syncrate ahc_syncrates[] = {
{ 0x00, 0x000, 0, NULL }
};
+void
+ahc_init_probe_config(struct ahc_probe_config *probe_config)
+{
+ probe_config->description = NULL;
+ probe_config->channel = 'A';
+ probe_config->channel_b = 'B';
+ probe_config->chip = AHC_NONE;
+ probe_config->features = AHC_FENONE;
+ probe_config->bugs = AHC_BUGNONE;
+ probe_config->flags = AHC_FNONE;
+}
+
/*
* Allocate a controller structure for a new device and initialize it.
*/
struct ahc_softc *
ahc_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id,
- bus_dma_tag_t parent_dmat, ahc_chip chip, ahc_feature features,
- ahc_flag flags, struct scb_data *scb_data)
+ bus_dma_tag_t parent_dmat, struct ahc_probe_config *config,
+ struct scb_data *scb_data)
{
/*
* find unit and check we have that many defined
*/
struct ahc_softc *ahc;
size_t alloc_size;
+ int i;
/*
- * Allocate a storage area for us
+ * Allocate a storage area for us.
*/
if (scb_data == NULL)
/*
@@ -786,9 +901,14 @@ ahc_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id,
ahc->tag = rman_get_bustag(regs);
ahc->bsh = rman_get_bushandle(regs);
ahc->parent_dmat = parent_dmat;
- ahc->chip = chip;
- ahc->features = features;
- ahc->flags = flags;
+ ahc->chip = config->chip;
+ ahc->features = config->features;
+ ahc->bugs = config->bugs;
+ ahc->flags = config->flags;
+ ahc->channel = config->channel;
+ for (i = 0; i < 16; i++)
+ TAILQ_INIT(&ahc->untagged_queues[i]);
+
if (scb_data == NULL) {
struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc;
ahc->scb_data = &full_softc->scb_data_storage;
@@ -1046,12 +1166,17 @@ int
ahc_reset(struct ahc_softc *ahc)
{
u_int sblkctl;
+ u_int sxfrctl1;
int wait;
#ifdef AHC_DUMP_SEQ
if (ahc->init_level == 0)
ahc_dumpseq(ahc);
#endif
+
+ /* Cache STPWEN. It is cleared by a chip reset */
+ pause_sequencer(ahc);
+ sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
/*
* Ensure that the reset has finished
@@ -1066,6 +1191,21 @@ ahc_reset(struct ahc_softc *ahc)
"Trying to initialize anyway.\n", ahc_name(ahc));
}
ahc_outb(ahc, HCNTRL, ahc->pause);
+ /*
+ * Reload sxfrctl1 with the cached value of STPWEN
+ * to minimize the amount of time our terminators
+ * are disabled. If a BIOS has initialized the chip,
+ * then sxfrctl1 will have the correct value. If
+ * not, STPWEN will be false (the value after a POST)
+ * and this action will be harmless.
+ *
+ * We must actually always initialize STPWEN to 1
+ * before we restore the saved value. STPWEN is
+ * initialized to a tri-state condition which is
+ * only be cleared by turning it on.
+ */
+ ahc_outb(ahc, SXFRCTL1, sxfrctl1|STPWEN);
+ ahc_outb(ahc, SXFRCTL1, sxfrctl1);
/* Determine channel configuration */
sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);
@@ -1098,22 +1238,25 @@ ahc_reset(struct ahc_softc *ahc)
* by the capabilities of the bus connectivity of the target.
*/
static struct ahc_syncrate *
-ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period) {
+ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period,
+ u_int *ppr_options) {
u_int maxsync;
if ((ahc->features & AHC_ULTRA2) != 0) {
if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0
&& (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) {
- maxsync = AHC_SYNCRATE_ULTRA2;
+ maxsync = AHC_SYNCRATE_DT;
} else {
maxsync = AHC_SYNCRATE_ULTRA;
+ /* Can't do DT on an SE bus */
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
}
} else if ((ahc->features & AHC_ULTRA) != 0) {
maxsync = AHC_SYNCRATE_ULTRA;
} else {
maxsync = AHC_SYNCRATE_FAST;
}
- return (ahc_find_syncrate(ahc, period, maxsync));
+ return (ahc_find_syncrate(ahc, period, ppr_options, maxsync));
}
/*
@@ -1122,14 +1265,30 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period) {
* if this was the beginning of an SDTR.
*/
static struct ahc_syncrate *
-ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync)
+ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+ u_int *ppr_options, u_int maxsync)
{
struct ahc_syncrate *syncrate;
- syncrate = &ahc_syncrates[maxsync];
- while ((syncrate->rate != NULL)
- && ((ahc->features & AHC_ULTRA2) == 0
- || (syncrate->sxfr_u2 != 0))) {
+ if ((ahc->features & AHC_DT) == 0)
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+
+ for (syncrate = &ahc_syncrates[maxsync];
+ syncrate->rate != NULL;
+ syncrate++) {
+
+ /*
+ * The Ultra2 table doesn't go as low
+ * as for the Fast/Ultra cards.
+ */
+ if ((ahc->features & AHC_ULTRA2) != 0
+ && (syncrate->sxfr_u2 == 0))
+ break;
+
+ /* Skip any DT entries if DT is not available */
+ if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+ && (syncrate->sxfr_u2 & DT_SXFR) != 0)
+ continue;
if (*period <= syncrate->period) {
/*
@@ -1145,9 +1304,15 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync)
*/
if (syncrate == &ahc_syncrates[maxsync])
*period = syncrate->period;
+
+ /*
+ * At some speeds, we only support
+ * ST transfers.
+ */
+ if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
break;
}
- syncrate++;
}
if ((*period == 0)
@@ -1157,6 +1322,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync)
/* Use asynchronous transfers. */
*period = 0;
syncrate = NULL;
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
}
return (syncrate);
}
@@ -1207,6 +1373,24 @@ ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate,
*offset = MIN(*offset, maxoffset);
}
+
+static void
+ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width)
+{
+ switch (*bus_width) {
+ default:
+ if (ahc->features & AHC_WIDE) {
+ /* Respond Wide */
+ *bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ break;
+ }
+ /* FALLTHROUGH */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
+ }
+}
+
static void
ahc_update_target_msg_request(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
@@ -1228,28 +1412,16 @@ 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 ((ahc->features & AHC_HS_MAILBOX) != 0) {
- if (paused) {
- ahc_outb(ahc, TARGET_MSG_REQUEST,
- ahc->targ_msg_req & 0xFF);
- ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
- (ahc->targ_msg_req >> 8) & 0xFF);
- } else {
- ahc_outb(ahc, HS_MAILBOX,
- 0x01 << HOST_MAILBOX_SHIFT);
- }
- } else {
- if (!paused)
- pause_sequencer(ahc);
+ if (!paused)
+ pause_sequencer(ahc);
- ahc_outb(ahc, TARGET_MSG_REQUEST,
- ahc->targ_msg_req & 0xFF);
- ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
- (ahc->targ_msg_req >> 8) & 0xFF);
+ ahc_outb(ahc, TARGET_MSG_REQUEST,
+ ahc->targ_msg_req & 0xFF);
+ ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
+ (ahc->targ_msg_req >> 8) & 0xFF);
- if (!paused)
- unpause_sequencer(ahc);
- }
+ if (!paused)
+ unpause_sequencer(ahc);
}
}
@@ -1272,7 +1444,8 @@ ahc_create_path(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
static void
ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
struct cam_path *path, struct ahc_syncrate *syncrate,
- u_int period, u_int offset, u_int type, int paused)
+ u_int period, u_int offset, u_int ppr_options,
+ u_int type, int paused)
{
struct ahc_initiator_tinfo *tinfo;
struct tmode_tstate *tstate;
@@ -1298,12 +1471,14 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
scsirate = tinfo->scsirate;
if ((ahc->features & AHC_ULTRA2) != 0) {
- /* XXX */
- /* Force single edge until DT is fully implemented */
scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC);
- if (syncrate != NULL)
- scsirate |= syncrate->sxfr_u2|SINGLE_EDGE;
-
+ if (syncrate != NULL) {
+ scsirate |= syncrate->sxfr_u2;
+ if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0)
+ scsirate |= ENABLE_CRC;
+ else
+ scsirate |= SINGLE_EDGE;
+ }
if (active)
ahc_outb(ahc, SCSIOFFSET, offset);
} else {
@@ -1338,6 +1513,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
tinfo->scsirate = scsirate;
tinfo->current.period = period;
tinfo->current.offset = offset;
+ tinfo->current.ppr_options = ppr_options;
/* Update the syncrates in any pending scbs */
ahc_update_pending_syncrates(ahc);
@@ -1361,6 +1537,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if (path != NULL) {
struct ccb_trans_settings neg;
+ neg.flags = CCB_TRANS_CURRENT_SETTINGS;
neg.sync_period = period;
neg.sync_offset = offset;
neg.valid = CCB_TRANS_SYNC_RATE_VALID
@@ -1374,9 +1551,11 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if (bootverbose) {
if (offset != 0) {
- printf("%s: target %d synchronous at %sMHz, "
+ printf("%s: target %d synchronous at %sMHz%s, "
"offset = 0x%x\n", ahc_name(ahc),
- devinfo->target, syncrate->rate, offset);
+ devinfo->target, syncrate->rate,
+ (ppr_options & MSG_EXT_PPR_DT_REQ)
+ ? " DT" : "", offset);
} else {
printf("%s: target %d using "
"asynchronous transfers\n",
@@ -1388,11 +1567,13 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if ((type & AHC_TRANS_GOAL) != 0) {
tinfo->goal.period = period;
tinfo->goal.offset = offset;
+ tinfo->goal.ppr_options = ppr_options;
}
if ((type & AHC_TRANS_USER) != 0) {
tinfo->user.period = period;
tinfo->user.offset = offset;
+ tinfo->user.ppr_options = ppr_options;
}
ahc_update_target_msg_request(ahc, devinfo, tinfo,
@@ -1444,6 +1625,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if (path != NULL) {
struct ccb_trans_settings neg;
+ neg.flags = CCB_TRANS_CURRENT_SETTINGS;
neg.bus_width = width;
neg.valid = CCB_TRANS_BUS_WIDTH_VALID;
xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
@@ -1634,18 +1816,18 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
our_id = scb->ccb->ccb_h.target_id;
role = ROLE_TARGET;
} else {
- our_id = SCB_CHANNEL(scb) == 'B' ? ahc->our_id_b : ahc->our_id;
+ our_id = SCB_GET_CHANNEL(scb) == 'B' ? ahc->our_id_b : ahc->our_id;
role = ROLE_INITIATOR;
}
- ahc_compile_devinfo(devinfo, our_id, SCB_TARGET(scb),
- SCB_LUN(scb), SCB_CHANNEL(scb), role);
+ ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),
+ SCB_GET_LUN(scb), SCB_GET_CHANNEL(scb), role);
}
#endif
static void
ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
- u_int saved_tcl;
+ u_int saved_scsiid;
role_t role;
int our_id;
@@ -1664,9 +1846,12 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
else
our_id = ahc_inb(ahc, SCSIID) & OID;
- saved_tcl = ahc_inb(ahc, SAVED_TCL);
- ahc_compile_devinfo(devinfo, our_id, TCL_TARGET(saved_tcl),
- TCL_LUN(saved_tcl), TCL_CHANNEL(ahc, saved_tcl),
+ saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+ ahc_compile_devinfo(devinfo,
+ our_id,
+ SCSIID_TARGET(ahc, saved_scsiid),
+ ahc_inb(ahc, SAVED_LUN),
+ SCSIID_CHANNEL(ahc, saved_scsiid),
role);
}
@@ -1723,9 +1908,8 @@ ahc_intr(void *arg)
if (intstat & CMDCMPLT) {
ahc_outb(ahc, CLRINT, CLRCMDINT);
ahc_run_qoutfifo(ahc);
- if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ if ((ahc->flags & AHC_TARGETMODE) != 0)
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
- }
}
if (intstat & BRKADRINT) {
/*
@@ -1748,10 +1932,14 @@ ahc_intr(void *arg)
CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
CAM_NO_HBA);
}
- if (intstat & SEQINT)
+
+ if ((intstat & (SEQINT|SCSIINT)) != 0)
+ ahc_pause_bug_fix(ahc);
+
+ if ((intstat & SEQINT) != 0)
ahc_handle_seqint(ahc, intstat);
- if (intstat & SCSIINT)
+ if ((intstat & SCSIINT) != 0)
ahc_handle_scsiint(ahc, intstat);
}
@@ -1826,8 +2014,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
struct tmode_lstate *lstate;
struct ccb_en_lun *cel;
cam_status status;
- int target;
- int lun;
+ u_int target;
+ u_int lun;
u_int target_mask;
char channel;
int s;
@@ -1922,7 +2110,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_update_scsiid(ahc, targid_mask);
} else {
- int our_id;
+ u_int our_id;
char channel;
channel = SIM_CHANNEL(ahc, sim);
@@ -2113,19 +2301,19 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
struct tmode_tstate *tstate;
struct tmode_lstate *lstate;
struct ccb_accept_tio *atio;
- u_int8_t *byte;
+ uint8_t *byte;
int initiator;
int target;
int lun;
- initiator = cmd->initiator_channel >> 4;
- target = cmd->targ_id;
+ initiator = SCSIID_TARGET(ahc, cmd->scsiid);
+ target = SCSIID_OUR_ID(cmd->scsiid);
lun = (cmd->identify & MSG_IDENTIFY_LUNMASK);
byte = cmd->bytes;
tstate = ahc->enabled_targets[target];
lstate = NULL;
- if (tstate != NULL && lun < 8)
+ if (tstate != NULL)
lstate = tstate->enabled_luns[lun];
/*
@@ -2168,9 +2356,9 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
atio->tag_id = *byte++;
atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
} else {
- byte++;
atio->ccb_h.flags = 0;
}
+ byte++;
/* Okay. Now determine the cdb size based on the command code */
switch (*byte >> CMD_GROUP_CODE_SHIFT) {
@@ -2210,6 +2398,8 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
initiator, target, lun, ahc->pending_device);
#endif
ahc->pending_device = lstate;
+ ahc_freeze_ccb((union ccb *)atio);
+ atio->ccb_h.flags |= CAM_DIS_DISCONNECT;
}
xpt_done((union ccb*)atio);
return (0);
@@ -2231,81 +2421,6 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
*/
ahc_outb(ahc, CLRINT, CLRSEQINT);
switch (intstat & SEQINT_MASK) {
- case NO_MATCH:
- {
- /* Ensure we don't leave the selection hardware on */
- ahc_outb(ahc, SCSISEQ,
- ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
-
- printf("%s:%c:%d: no active SCB for reconnecting "
- "target - issuing BUS DEVICE RESET\n",
- ahc_name(ahc), devinfo.channel, devinfo.target);
- printf("SAVED_TCL == 0x%x, ARG_1 == 0x%x, SEQ_FLAGS == 0x%x\n",
- ahc_inb(ahc, SAVED_TCL), ahc_inb(ahc, ARG_1),
- ahc_inb(ahc, SEQ_FLAGS));
- ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
- ahc->msgout_len = 1;
- ahc->msgout_index = 0;
- ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
- ahc_outb(ahc, MSG_OUT, HOST_MSG);
- ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
- break;
- }
- case UPDATE_TMSG_REQ:
- ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF);
- ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
- (ahc->targ_msg_req >> 8) & 0xFF);
- ahc_outb(ahc, HS_MAILBOX, 0);
- break;
- case SEND_REJECT:
- {
- u_int rejbyte = ahc_inb(ahc, ACCUM);
- printf("%s:%c:%d: Warning - unknown message received from "
- "target (0x%x). Rejecting\n",
- ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
- break;
- }
- case NO_IDENT:
- {
- /*
- * The reconnecting target either did not send an identify
- * message, or did, but we didn't find and SCB to match and
- * before it could respond to our ATN/abort, it hit a dataphase.
- * The only safe thing to do is to blow it away with a bus
- * reset.
- */
- int found;
-
- printf("%s:%c:%d: Target did not send an IDENTIFY message. "
- "LASTPHASE = 0x%x, SAVED_TCL == 0x%x\n",
- ahc_name(ahc), devinfo.channel, devinfo.target,
- ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_TCL));
- found = ahc_reset_channel(ahc, devinfo.channel,
- /*initiate reset*/TRUE);
- printf("%s: Issued Channel %c Bus Reset. "
- "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
- found);
- return;
- }
- case BAD_PHASE:
- {
- u_int lastphase;
-
- lastphase = ahc_inb(ahc, LASTPHASE);
- if (lastphase == P_BUSFREE) {
- printf("%s:%c:%d: Missed busfree. Curphase = 0x%x\n",
- ahc_name(ahc), devinfo.channel, devinfo.target,
- ahc_inb(ahc, SCSISIGI));
- restart_sequencer(ahc);
- return;
- } else {
- printf("%s:%c:%d: unknown scsi bus phase %x. "
- "Attempting to continue\n",
- ahc_name(ahc), devinfo.channel, devinfo.target,
- ahc_inb(ahc, SCSISIGI));
- }
- break;
- }
case BAD_STATUS:
{
u_int scb_index;
@@ -2352,12 +2467,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
break;
}
ahcsetccbstatus(scb->ccb, CAM_SCSI_STATUS_ERROR);
- /* Freeze the queue unit the client sees the error. */
+ /* Freeze the queue until the client sees the error. */
ahc_freeze_devq(ahc, scb->ccb->ccb_h.path);
ahc_freeze_ccb(scb->ccb);
csio = &scb->ccb->csio;
- csio->scsi_status = hscb->status;
- switch (hscb->status) {
+ csio->scsi_status = hscb->shared_data.status.scsi_status;
+ switch (csio->scsi_status) {
case SCSI_STATUS_OK:
printf("%s: Interrupted for staus of 0???\n",
ahc_name(ahc));
@@ -2371,19 +2486,27 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb->hscb->tag);
}
#endif
-
if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
struct ahc_dma_seg *sg;
struct scsi_sense *sc;
- struct ahc_initiator_tinfo *tinfo;
+ struct ahc_initiator_tinfo *targ_info;
struct tmode_tstate *tstate;
-
+ struct ahc_transinfo *tinfo;
+
+ targ_info =
+ ahc_fetch_transinfo(ahc,
+ devinfo.channel,
+ devinfo.our_scsiid,
+ devinfo.target,
+ &tstate);
+ tinfo = &targ_info->current;
sg = scb->sg_list;
- sc = (struct scsi_sense *)(&hscb->cmdstore);
+ sc = (struct scsi_sense *)
+ (&hscb->shared_data.cdb);
/*
* Save off the residual if there is one.
*/
- if (hscb->residual_SG_count != 0)
+ if (ahc_check_residual(scb))
ahc_calc_residual(scb);
else
scb->ccb->csio.resid = 0;
@@ -2398,9 +2521,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
+ (hscb->tag*sizeof(struct scsi_sense_data));
sg->len = MIN(sizeof(struct scsi_sense_data),
csio->sense_len);
+ sg->len |= AHC_DMA_LAST_SEG;
sc->opcode = REQUEST_SENSE;
- sc->byte2 = SCB_LUN(scb) << 5;
+ sc->byte2 = 0;
+ if (tinfo->protocol_version <= SCSI_REV_2
+ && SCB_GET_LUN(scb) < 8)
+ sc->byte2 = SCB_GET_LUN(scb) << 5;
sc->unused[0] = 0;
sc->unused[1] = 0;
sc->length = sg->len;
@@ -2408,7 +2535,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
/*
* Would be nice to preserve DISCENB here,
- * but due to the way we page SCBs, we can't.
+ * but due to the way we manage busy targets,
+ * we can't.
*/
hscb->control = 0;
@@ -2420,34 +2548,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* errors will be reported before any data
* phases occur.
*/
- ahc_calc_residual(scb);
if (scb->ccb->csio.resid
== scb->ccb->csio.dxfer_len) {
- tinfo = ahc_fetch_transinfo(ahc,
- devinfo.channel,
- devinfo.our_scsiid,
- devinfo.target,
- &tstate);
ahc_update_target_msg_request(ahc,
&devinfo,
- tinfo,
+ targ_info,
/*force*/TRUE,
/*paused*/TRUE);
}
- hscb->status = 0;
- hscb->SG_count = 1;
- hscb->SG_pointer = scb->sg_list_phys;
- hscb->data = sg->addr;
- hscb->datalen = sg->len;
- hscb->cmdpointer = hscb->cmdstore_busaddr;
- hscb->cmdlen = sizeof(*sc);
- scb->sg_count = hscb->SG_count;
+ hscb->cdb_len = sizeof(*sc);
+ hscb->dataptr = sg->addr;
+ hscb->datacnt = sg->len;
+ hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+ scb->sg_count = 1;
scb->flags |= SCB_SENSE;
- /*
- * Ensure the target is busy since this
- * will be an untagged request.
- */
- ahc_busy_tcl(ahc, scb);
ahc_outb(ahc, RETURN_1, SEND_SENSE);
/*
@@ -2460,29 +2574,89 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
}
break;
- case SCSI_STATUS_BUSY:
- case SCSI_STATUS_QUEUE_FULL:
- /*
- * Requeue any transactions that haven't been
- * sent yet.
- */
- ahc_freeze_devq(ahc, scb->ccb->ccb_h.path);
- ahc_freeze_ccb(scb->ccb);
+ default:
break;
}
break;
}
- case TRACE_POINT:
+ case NO_MATCH:
{
- printf("SSTAT2 = 0x%x DFCNTRL = 0x%x\n", ahc_inb(ahc, SSTAT2),
- ahc_inb(ahc, DFCNTRL));
- printf("SSTAT3 = 0x%x DSTATUS = 0x%x\n", ahc_inb(ahc, SSTAT3),
- ahc_inb(ahc, DFSTATUS));
- printf("SSTAT0 = 0x%x, SCB_DATACNT = 0x%x\n",
- ahc_inb(ahc, SSTAT0),
- ahc_inb(ahc, SCB_DATACNT));
+ /* Ensure we don't leave the selection hardware on */
+ ahc_outb(ahc, SCSISEQ,
+ ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+ printf("%s:%c:%d: no active SCB for reconnecting "
+ "target - issuing BUS DEVICE RESET\n",
+ ahc_name(ahc), devinfo.channel, devinfo.target);
+ printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+ "ARG_1 == 0x%x ARG_2 = 0x%x, SEQ_FLAGS == 0x%x\n",
+ ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+ ahc_inb(ahc, ARG_1), ahc_inb(ahc, ARG_2),
+ ahc_inb(ahc, SEQ_FLAGS));
+ printf("SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+ "SCB_TAG == 0x%x\n",
+ ahc_inb(ahc, SCB_SCSIID), ahc_inb(ahc, SCB_LUN),
+ ahc_inb(ahc, SCB_TAG));
+ ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
+ ahc->msgout_len = 1;
+ ahc->msgout_index = 0;
+ ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+ ahc_outb(ahc, MSG_OUT, HOST_MSG);
+ ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
break;
}
+ case SEND_REJECT:
+ {
+ u_int rejbyte = ahc_inb(ahc, ACCUM);
+ printf("%s:%c:%d: Warning - unknown message received from "
+ "target (0x%x). Rejecting\n",
+ ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
+ break;
+ }
+ case NO_IDENT:
+ {
+ /*
+ * The reconnecting target either did not send an identify
+ * message, or did, but we didn't find an SCB to match and
+ * before it could respond to our ATN/abort, it hit a dataphase.
+ * The only safe thing to do is to blow it away with a bus
+ * reset.
+ */
+ int found;
+
+ printf("%s:%c:%d: Target did not send an IDENTIFY message. "
+ "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n",
+ ahc_name(ahc), devinfo.channel, devinfo.target,
+ ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID));
+ found = ahc_reset_channel(ahc, devinfo.channel,
+ /*initiate reset*/TRUE);
+ printf("%s: Issued Channel %c Bus Reset. "
+ "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
+ found);
+ return;
+ }
+ case IGN_WIDE_RES:
+ ahc_handle_ign_wide_residue(ahc, &devinfo);
+ break;
+ case BAD_PHASE:
+ {
+ u_int lastphase;
+
+ lastphase = ahc_inb(ahc, LASTPHASE);
+ if (lastphase == P_BUSFREE) {
+ printf("%s:%c:%d: Missed busfree. Curphase = 0x%x\n",
+ ahc_name(ahc), devinfo.channel, devinfo.target,
+ ahc_inb(ahc, SCSISIGI));
+ restart_sequencer(ahc);
+ return;
+ } else {
+ printf("%s:%c:%d: unknown scsi bus phase %x. "
+ "Attempting to continue\n",
+ ahc_name(ahc), devinfo.channel, devinfo.target,
+ ahc_inb(ahc, SCSISIGI));
+ }
+ break;
+ }
case HOST_MSG_LOOP:
{
/*
@@ -2490,10 +2664,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* that requires host assistance for completion.
* While handling the message phase(s), we will be
* notified by the sequencer after each byte is
- * transfered so we can track bus phases.
+ * transfered so we can track bus phase changes.
*
- * If this is the first time we've seen a HOST_MSG_LOOP,
- * initialize the state of the host message loop.
+ * If this is the first time we've seen a HOST_MSG_LOOP
+ * interrupt, initialize the state of the host message
+ * loop.
*/
if (ahc->msg_type == MSG_TYPE_NONE) {
u_int bus_phase;
@@ -2510,6 +2685,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
*/
ahc_clear_intstat(ahc);
restart_sequencer(ahc);
+ return;
}
if (devinfo.role == ROLE_INITIATOR) {
@@ -2585,7 +2761,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
*/
u_int scbindex = ahc_inb(ahc, SCB_TAG);
u_int lastphase = ahc_inb(ahc, LASTPHASE);
- int i;
+ u_int i;
scb = &ahc->scb_data->scbarray[scbindex];
for (i = 0; i < num_phases; i++) {
@@ -2606,11 +2782,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
printf("sg[%d] - Addr 0x%x : Length %d\n",
i,
scb->sg_list[i].addr,
- scb->sg_list[i].len);
+ scb->sg_list[i].len & AHC_SG_LEN_MASK);
}
}
/*
- * Set this and it will take affect when the
+ * Set this and it will take effect when the
* target does a command complete.
*/
ahc_freeze_devq(ahc, scb->ccb->ccb_h.path);
@@ -2620,7 +2796,79 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
}
case TRACEPOINT:
{
- printf("TRACEPOINT: RETURN_2 = %d\n", ahc_inb(ahc, RETURN_2));
+ printf("SAVED_SCSIID %x, SAVED_LUN %x, SCBPTR %x\n",
+ ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+ ahc_inb(ahc, SCBPTR));
+#if 0
+ printf("%s: SCB_DATAPTR = %x, SCB_DATACNT = %x\n",
+ ahc_name(ahc),
+ ahc_inb(ahc, SCB_DATAPTR)
+ | (ahc_inb(ahc, SCB_DATAPTR + 1) << 8)
+ | (ahc_inb(ahc, SCB_DATAPTR + 2) << 16)
+ | (ahc_inb(ahc, SCB_DATAPTR + 3) << 24),
+ ahc_inb(ahc, SCB_DATACNT)
+ | (ahc_inb(ahc, SCB_DATACNT + 1) << 8)
+ | (ahc_inb(ahc, SCB_DATACNT + 2) << 16)
+ | (ahc_inb(ahc, SCB_DATACNT + 3) << 24));
+ printf("SCSIRATE = %x\n", ahc_inb(ahc, SCSIRATE));
+ printf("SG_CACHEPTR = %x\n", ahc_inb(ahc, SINDEX));
+ printf("DFCNTRL = %x, DFSTATUS = %x\n",
+ ahc_inb(ahc, DFCNTRL),
+ ahc_inb(ahc, DFSTATUS));
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ printf("CCHADDR = 0x%x\n",
+ ahc_inb(ahc, CCHADDR)
+ | (ahc_inb(ahc, CCHADDR + 1) << 8)
+ | (ahc_inb(ahc, CCHADDR + 2) << 16)
+ | (ahc_inb(ahc, CCHADDR + 3) << 24));
+ } else {
+ printf("HADDR = 0x%x\n",
+ ahc_inb(ahc, HADDR)
+ | (ahc_inb(ahc, HADDR + 1) << 8)
+ | (ahc_inb(ahc, HADDR + 2) << 16)
+ | (ahc_inb(ahc, HADDR + 3) << 24));
+ }
+
+#endif
+ break;
+ }
+ case TRACEPOINT2:
+ {
+ printf("SINDEX = %x\n", ahc_inb(ahc, SINDEX));
+ printf("SCSIRATE = %x\n", ahc_inb(ahc, SCSIRATE));
+#if 0
+ printf("SCB_RESIDUAL_SGPTR = %x, SCB_RESIDUAL_DATACNT = %x\n",
+ ahc_inb(ahc, SCB_RESIDUAL_SGPTR)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24),
+ ahc_inb(ahc, SCB_RESIDUAL_DATACNT)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 3) << 24));
+ printf("DATA_COUNT_ODD = %x\n", ahc_inb(ahc, DATA_COUNT_ODD));
+ printf("SINDEX = %x\n", ahc_inb(ahc, SINDEX));
+ printf("SCB_SGPTR %x, SCB_RESIDUAL_SGPTR %x\n",
+ ahc_inb(ahc, SCB_SGPTR),
+ ahc_inb(ahc, SCB_RESIDUAL_SGPTR));
+ printf("SAVED_SCSIID %x, SAVED_LUN %d, "
+ "DISCONNECTED_SCBH %d\n",
+ ahc_inb(ahc, SAVED_SCSIID),
+ ahc_inb(ahc, SAVED_LUN),
+ ahc_inb(ahc, DISCONNECTED_SCBH));
+ int i;
+
+ if (ahc->unit != 1)
+ break;
+ for (i = 0; i < 32;) {
+ printf("0x%x 0x%x 0x%x 0x%x\n",
+ ahc_inb(ahc, SCB_CONTROL + i),
+ ahc_inb(ahc, SCB_CONTROL + i + 1),
+ ahc_inb(ahc, SCB_CONTROL + i + 2),
+ ahc_inb(ahc, SCB_CONTROL + i + 3));
+ i += 4;
+ }
+#endif
#if 0
printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1));
printf("SSTAT0 == 0x%x\n", ahc_inb(ahc, SSTAT0));
@@ -2642,13 +2890,6 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
#endif
break;
}
-#if NOT_YET
- /* XXX Fill these in later */
- case MESG_BUFFER_BUSY:
- break;
- case MSGIN_PHASEMIS:
- break;
-#endif
default:
printf("ahc_intr: seqint, "
"intstat == 0x%x, scsisigi = 0x%x\n",
@@ -2724,7 +2965,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
u_int curphase;
u_int errorphase;
u_int lastphase;
- int i;
+ u_int i;
lastphase = ahc_inb(ahc, LASTPHASE);
curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
@@ -2756,7 +2997,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
else
printf("%s:%c:%d: ", ahc_name(ahc),
intr_channel,
- TCL_TARGET(ahc_inb(ahc, SAVED_TCL)));
+ SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
printf("parity error detected %s. "
"SEQADDR(0x%x) SCSIRATE(0x%x)\n",
@@ -2788,10 +3029,11 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* our abort requests.
*/
u_int lastphase = ahc_inb(ahc, LASTPHASE);
- u_int saved_tcl = ahc_inb(ahc, SAVED_TCL);
- u_int target = TCL_TARGET(saved_tcl);
- u_int initiator_role_id = TCL_SCSI_ID(ahc, saved_tcl);
- char channel = TCL_CHANNEL(ahc, saved_tcl);
+ u_int saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+ u_int saved_lun = ahc_inb(ahc, SAVED_LUN);
+ u_int target = SCSIID_TARGET(ahc, saved_scsiid);
+ u_int initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
+ char channel = SCSIID_CHANNEL(ahc, saved_scsiid);
int printerror = 1;
ahc_outb(ahc, SCSISEQ,
@@ -2812,7 +3054,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
scb->hscb->tag, tag == SCB_LIST_NULL ?
"" : "Tag");
ahc_abort_scbs(ahc, target, channel,
- TCL_LUN(saved_tcl), tag,
+ saved_lun, tag,
ROLE_INITIATOR,
CAM_REQ_ABORTED);
printerror = 0;
@@ -2828,8 +3070,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
*/
if (scb != NULL
&& scb->ccb->ccb_h.func_code == XPT_RESET_DEV
- && ahc_match_scb(scb, target, channel,
- TCL_LUN(saved_tcl),
+ && ahc_match_scb(ahc, scb, target, channel,
+ saved_lun,
SCB_LIST_NULL,
ROLE_INITIATOR)) {
ahcsetccbstatus(scb->ccb, CAM_REQ_CMP);
@@ -2837,7 +3079,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_compile_devinfo(&devinfo,
initiator_role_id,
target,
- TCL_LUN(saved_tcl),
+ saved_lun,
channel,
ROLE_INITIATOR);
ahc_handle_devreset(ahc, &devinfo,
@@ -2852,7 +3094,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
}
}
if (printerror != 0) {
- int i;
+ u_int i;
if (scb != NULL) {
u_int tag;
@@ -2862,7 +3104,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
else
tag = SCB_LIST_NULL;
ahc_abort_scbs(ahc, target, channel,
- SCB_LUN(scb), tag,
+ SCB_GET_LUN(scb), tag,
ROLE_INITIATOR,
CAM_UNEXP_BUSFREE);
xpt_print_path(scb->ccb->ccb_h.path);
@@ -2906,15 +3148,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
} else {
- u_int tag;
-
- tag = SCB_LIST_NULL;
- if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0)
- tag = scb->hscb->tag;
-
- ahc_abort_scbs(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
- SCB_LUN(scb), tag,
- ROLE_INITIATOR, CAM_SEL_TIMEOUT);
+ ahcsetccbstatus(scb->ccb, CAM_SEL_TIMEOUT);
+ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path);
}
/* Stop the selection */
ahc_outb(ahc, SCSISEQ, 0);
@@ -2926,7 +3161,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* Although the driver does not care about the
* 'Selection in Progress' status bit, the busy
* LED does. SELINGO is only cleared by a sucessful
- * selection, so we must manually clear it to ensure
+ * selection, so we must manually clear it to insure
* the LED turns off just incase no future successful
* selections occur (e.g. no devices on the bus).
*/
@@ -2955,35 +3190,47 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
struct ahc_initiator_tinfo *tinfo;
struct tmode_tstate *tstate;
+ struct ahc_syncrate *rate;
int dowide;
int dosync;
+ int doppr;
+ int use_ppr;
+ u_int period;
+ u_int ppr_options;
+ u_int offset;
tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
devinfo->target, &tstate);
dowide = tinfo->current.width != tinfo->goal.width;
dosync = tinfo->current.period != tinfo->goal.period;
+ doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options;
- if (!dowide && !dosync) {
+ if (!dowide && !dosync && !doppr) {
dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
dosync = tinfo->goal.period != 0;
+ doppr = tinfo->goal.ppr_options != 0;
}
- if (dowide) {
+ if (!dowide && !dosync && !doppr) {
+ panic("ahc_intr: AWAITING_MSG for negotiation, "
+ "but no negotiation needed\n");
+ }
+
+ use_ppr = (tinfo->current.transport_version >= 3) || doppr;
+ if (use_ppr) {
+ ahc_construct_ppr(ahc, tinfo->goal.period, tinfo->goal.offset,
+ tinfo->goal.width, tinfo->goal.ppr_options);
+ } else if (dowide) {
ahc_construct_wdtr(ahc, tinfo->goal.width);
} else if (dosync) {
- struct ahc_syncrate *rate;
- u_int period;
- u_int offset;
period = tinfo->goal.period;
- rate = ahc_devlimited_syncrate(ahc, &period);
+ ppr_options = 0;
+ rate = ahc_devlimited_syncrate(ahc, &period, &ppr_options);
offset = tinfo->goal.offset;
ahc_validate_offset(ahc, rate, &offset,
tinfo->current.width);
ahc_construct_sdtr(ahc, period, offset);
- } else {
- panic("ahc_intr: AWAITING_MSG for negotiation, "
- "but no negotiation needed\n");
}
}
@@ -3003,7 +3250,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
&& ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) {
u_int identify_msg;
- identify_msg = MSG_IDENTIFYFLAG | SCB_LUN(scb);
+ identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb);
if ((scb->hscb->control & DISCENB) != 0)
identify_msg |= MSG_IDENTIFY_DISCFLAG;
ahc->msgout_buf[ahc->msgout_index++] = identify_msg;
@@ -3022,7 +3269,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_len++;
xpt_print_path(scb->ccb->ccb_h.path);
printf("Bus Device Reset Message Sent\n");
- } else if (scb->flags & SCB_ABORT) {
+ } else if ((scb->flags & SCB_ABORT) != 0) {
if ((scb->hscb->control & TAG_ENB) != 0)
ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG;
else
@@ -3030,11 +3277,14 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_len++;
xpt_print_path(scb->ccb->ccb_h.path);
printf("Abort Message Sent\n");
- } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0) {
+ } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0
+ || (scb->flags & SCB_NEGOTIATE) != 0) {
ahc_build_transfer_msg(ahc, devinfo);
} else {
printf("ahc_intr: AWAITING_MSG for an SCB that "
- "does not have a waiting message");
+ "does not have a waiting message\n");
+ printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+ devinfo->target_mask);
panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
"SCB flags = %x", scb->hscb->tag, scb->hscb->control,
ahc_inb(ahc, MSG_OUT), scb->flags);
@@ -3079,6 +3329,8 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* the target is refusing negotiation.
*/
struct scb *scb;
+ struct ahc_initiator_tinfo *tinfo;
+ struct tmode_tstate *tstate;
u_int scb_index;
u_int last_msg;
int response = 0;
@@ -3086,12 +3338,13 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
scb_index = ahc_inb(ahc, SCB_TAG);
scb = &ahc->scb_data->scbarray[scb_index];
+ tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+ devinfo->our_scsiid,
+ devinfo->target, &tstate);
/* Might be necessary */
last_msg = ahc_inb(ahc, LAST_MSG);
if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) {
- struct ahc_initiator_tinfo *tinfo;
- struct tmode_tstate *tstate;
/* note 8bit xfers */
printf("%s:%c:%d: refuses WIDE negotiation. Using "
@@ -3108,15 +3361,14 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* but rejected our response, we already cleared the
* sync rate before sending our WDTR.
*/
- tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
- devinfo->our_scsiid,
- devinfo->target, &tstate);
if (tinfo->goal.period) {
u_int period;
+ u_int ppr_options;
/* Start the sync negotiation */
period = tinfo->goal.period;
- ahc_devlimited_syncrate(ahc, &period);
+ ppr_options = 0;
+ ahc_devlimited_syncrate(ahc, &period, &ppr_options);
ahc->msgout_index = 0;
ahc->msgout_len = 0;
ahc_construct_sdtr(ahc, period, tinfo->goal.offset);
@@ -3127,7 +3379,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
/* note asynch xfers and clear flag */
ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path,
/*syncrate*/NULL, /*period*/0,
- /*offset*/0,
+ /*offset*/0, /*ppr_options*/0,
AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
/*paused*/TRUE);
printf("%s:%c:%d: refuses synchronous negotiation. "
@@ -3142,7 +3394,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
devinfo->channel, devinfo->target);
ahc_set_tags(ahc, devinfo, FALSE);
- neg.flags = 0;
+ neg.flags = CCB_TRANS_CURRENT_SETTINGS;
neg.valid = CCB_TRANS_TQ_VALID;
xpt_setup_ccb(&neg.ccb_h, scb->ccb->ccb_h.path, /*priority*/1);
xpt_async(AC_TRANSFER_NEG, scb->ccb->ccb_h.path, &neg);
@@ -3163,8 +3415,9 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* currently in our posession so they can be
* converted to untagged commands.
*/
- ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
- SCB_LUN(scb), /*tag*/SCB_LIST_NULL,
+ ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+ SCB_GET_CHANNEL(ahc, scb),
+ SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL,
ROLE_INITIATOR, CAM_REQUEUE_REQ,
SEARCH_COMPLETE);
} else {
@@ -3444,7 +3697,7 @@ static int
ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full)
{
int found;
- int index;
+ u_int index;
found = FALSE;
index = 0;
@@ -3514,19 +3767,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
case MSG_NOOP:
done = MSGLOOP_MSGCOMPLETE;
break;
- case MSG_IGN_WIDE_RESIDUE:
- {
- /* Wait for the whole message */
- if (ahc->msgin_index >= 1) {
- if (ahc->msgin_buf[1] != 1
- || tinfo->current.width == MSG_EXT_WDTR_BUS_8_BIT) {
- reject = TRUE;
- done = MSGLOOP_MSGCOMPLETE;
- } else
- ahc_handle_ign_wide_residue(ahc, devinfo);
- }
- break;
- }
case MSG_EXTENDED:
{
/* Wait for enough of the message to begin validation */
@@ -3537,6 +3777,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
{
struct ahc_syncrate *syncrate;
u_int period;
+ u_int ppr_options;
u_int offset;
u_int saved_offset;
@@ -3556,12 +3797,15 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
break;
period = ahc->msgin_buf[3];
+ ppr_options = 0;
saved_offset = offset = ahc->msgin_buf[4];
- syncrate = ahc_devlimited_syncrate(ahc, &period);
+ syncrate = ahc_devlimited_syncrate(ahc, &period,
+ &ppr_options);
ahc_validate_offset(ahc, syncrate, &offset,
targ_scsirate & WIDEXFER);
ahc_set_syncrate(ahc, devinfo, path,
- syncrate, period, offset,
+ syncrate, period,
+ offset, ppr_options,
AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
/*paused*/TRUE);
@@ -3593,8 +3837,9 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
}
case MSG_EXT_WDTR:
{
- u_int bus_width;
- u_int sending_reply;
+ u_int bus_width;
+ u_int saved_width;
+ u_int sending_reply;
sending_reply = FALSE;
if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) {
@@ -3613,29 +3858,23 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
break;
bus_width = ahc->msgin_buf[3];
+ saved_width = bus_width;
+ ahc_validate_width(ahc, &bus_width);
+
if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/TRUE)) {
/*
* Don't send a WDTR back to the
* target, since we asked first.
+ * If the width went higher than our
+ * request, reject it.
*/
- switch (bus_width){
- default:
- /*
- * How can we do anything greater
- * than 16bit transfers on a 16bit
- * bus?
- */
+ if (saved_width > bus_width) {
reject = TRUE;
printf("%s: target %d requested %dBit "
"transfers. Rejecting...\n",
ahc_name(ahc), devinfo->target,
8 * (0x01 << bus_width));
- /* FALLTHROUGH */
- case MSG_EXT_WDTR_BUS_8_BIT:
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- case MSG_EXT_WDTR_BUS_16_BIT:
- break;
+ bus_width = 0;
}
} else {
/*
@@ -3643,19 +3882,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
*/
if (bootverbose)
printf("Sending WDTR!\n");
- switch (bus_width) {
- default:
- if (ahc->features & AHC_WIDE) {
- /* Respond Wide */
- bus_width =
- MSG_EXT_WDTR_BUS_16_BIT;
- break;
- }
- /* FALLTHROUGH */
- case MSG_EXT_WDTR_BUS_8_BIT:
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- }
ahc->msgout_index = 0;
ahc->msgout_len = 0;
ahc_construct_wdtr(ahc, bus_width);
@@ -3670,19 +3896,23 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
/* After a wide message, we are async */
ahc_set_syncrate(ahc, devinfo, path,
/*syncrate*/NULL, /*period*/0,
- /*offset*/0, AHC_TRANS_ACTIVE,
- /*paused*/TRUE);
+ /*offset*/0, /*ppr_options*/0,
+ AHC_TRANS_ACTIVE, /*paused*/TRUE);
if (sending_reply == FALSE && reject == FALSE) {
+ /* XXX functionalize */
if (tinfo->goal.period) {
struct ahc_syncrate *rate;
u_int period;
+ u_int ppr;
u_int offset;
/* Start the sync negotiation */
period = tinfo->goal.period;
+ ppr = 0;
rate = ahc_devlimited_syncrate(ahc,
- &period);
+ &period,
+ &ppr);
offset = tinfo->goal.offset;
ahc_validate_offset(ahc, rate, &offset,
tinfo->current.width);
@@ -3696,6 +3926,86 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path,
done = MSGLOOP_MSGCOMPLETE;
break;
}
+ case MSG_EXT_PPR:
+ {
+ struct ahc_syncrate *syncrate;
+ u_int period;
+ u_int offset;
+ u_int bus_width;
+ u_int ppr_options;
+ u_int saved_width;
+ u_int saved_offset;
+ u_int saved_ppr_options;
+
+ if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) {
+ reject = TRUE;
+ break;
+ }
+
+ /*
+ * Wait until we have all args before validating
+ * and acting on this message.
+ *
+ * Add one to MSG_EXT_PPR_LEN to account for
+ * the extended message preamble.
+ */
+ if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1))
+ break;
+
+ period = ahc->msgin_buf[3];
+ offset = ahc->msgin_buf[5];
+ bus_width = ahc->msgin_buf[6];
+ saved_width = bus_width;
+ ppr_options = ahc->msgin_buf[7];
+ /*
+ * According to the spec, a DT only
+ * period factor with no DT option
+ * set implies async.
+ */
+ if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+ && period == 9)
+ offset = 0;
+ saved_ppr_options = ppr_options;
+ saved_offset = offset;
+
+ /*
+ * Mask out any options we don't support
+ * on any controller. Transfer options are
+ * only available if we are negotiating wide.
+ */
+ ppr_options &= MSG_EXT_PPR_DT_REQ;
+ if (bus_width == 0)
+ ppr_options = 0;
+
+ ahc_validate_width(ahc, &bus_width);
+ syncrate = ahc_devlimited_syncrate(ahc, &period,
+ &ppr_options);
+ ahc_validate_offset(ahc, syncrate, &offset, bus_width);
+
+ if (ahc_sent_msg(ahc, MSG_EXT_PPR, /*full*/TRUE)) {
+ /*
+ * If we are unable to do any of the
+ * requested options (we went too low),
+ * then we'll have to reject the message.
+ */
+ if (saved_width > bus_width
+ || saved_offset != offset
+ || saved_ppr_options != ppr_options)
+ reject = TRUE;
+ } else {
+ printf("Target Initated PPR detected!\n");
+ response = TRUE;
+ }
+ ahc_set_syncrate(ahc, devinfo, path,
+ syncrate, period,
+ offset, ppr_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+ /*paused*/TRUE);
+ ahc_set_width(ahc, devinfo, path, bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+ /*paused*/TRUE);
+ break;
+ }
default:
/* Unknown extended message. Reject it. */
reject = TRUE;
@@ -3787,10 +4097,10 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* nothing. Otherwise, subtract a byte
* and update the residual count accordingly.
*/
- u_int resid_sgcnt;
+ uint32_t sgptr;
- resid_sgcnt = ahc_inb(ahc, SCB_RESID_SGCNT);
- if (resid_sgcnt == 0
+ sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
+ if ((sgptr & SG_LIST_NULL) != 0
&& ahc_inb(ahc, DATA_COUNT_ODD) == 1) {
/*
* If the residual occurred on the last
@@ -3799,13 +4109,18 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* nothing.
*/
} else {
- u_int data_cnt;
- u_int data_addr;
- u_int sg_index;
-
- data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16)
- | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8)
- | (ahc_inb(ahc, SCB_RESID_DCNT));
+ struct ahc_dma_seg *sg;
+ uint32_t data_cnt;
+ uint32_t data_addr;
+
+ /* Pull in the rest of the sgptr */
+ sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8);
+ sgptr &= SG_PTR_MASK;
+ data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT));
data_addr = (ahc_inb(ahc, SHADDR + 3) << 24)
| (ahc_inb(ahc, SHADDR + 2) << 16)
@@ -3815,38 +4130,56 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
data_cnt += 1;
data_addr -= 1;
- sg_index = scb->sg_count - resid_sgcnt;
+ sg = ahc_sg_bus_to_virt(scb, sgptr);
+ /*
+ * The residual sg ptr points to the next S/G
+ * to load so we must go back one.
+ */
+ sg--;
+ if (sg != scb->sg_list
+ && (sg->len & AHC_SG_LEN_MASK) < data_cnt) {
- if (sg_index != 0
- && (scb->sg_list[sg_index].len < data_cnt)) {
- u_int sg_addr;
+ sg--;
+ data_cnt = 1 | (sg->len & AHC_DMA_LAST_SEG);
+ data_addr = sg->addr
+ + (sg->len & AHC_SG_LEN_MASK) - 1;
- sg_index--;
- data_cnt = 1;
- data_addr = scb->sg_list[sg_index].addr
- + scb->sg_list[sg_index].len - 1;
-
/*
- * The physical address base points to the
- * second entry as it is always used for
- * calculating the "next S/G pointer".
+ * Increment sg so it points to the
+ * "next" sg.
*/
- sg_addr = scb->sg_list_phys
- + (sg_index* sizeof(*scb->sg_list));
- ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24);
- ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16);
- ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8);
- ahc_outb(ahc, SG_NEXT, sg_addr);
+ sg++;
+ sgptr = ahc_sg_virt_to_bus(scb, sg);
+ ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3,
+ sgptr >> 24);
+ ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2,
+ sgptr >> 16);
+ ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1,
+ sgptr >> 8);
+ ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr);
}
- ahc_outb(ahc, SCB_RESID_DCNT + 2, data_cnt >> 16);
- ahc_outb(ahc, SCB_RESID_DCNT + 1, data_cnt >> 8);
- ahc_outb(ahc, SCB_RESID_DCNT, data_cnt);
+/* XXX What about high address byte??? */
+ ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24);
+ ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16);
+ ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8);
+ ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
- ahc_outb(ahc, SHADDR + 3, data_addr >> 24);
- ahc_outb(ahc, SHADDR + 2, data_addr >> 16);
- ahc_outb(ahc, SHADDR + 1, data_addr >> 8);
- ahc_outb(ahc, SHADDR, data_addr);
+/* XXX Perhaps better to just keep the saved address in sram */
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ ahc_outb(ahc, HADDR + 3, data_addr >> 24);
+ ahc_outb(ahc, HADDR + 2, data_addr >> 16);
+ ahc_outb(ahc, HADDR + 1, data_addr >> 8);
+ ahc_outb(ahc, HADDR, data_addr);
+ ahc_outb(ahc, DFCNTRL, PRELOADEN);
+ ahc_outb(ahc, SXFRCTL0,
+ ahc_inb(ahc, SXFRCTL0) | CLRCHN);
+ } else {
+ ahc_outb(ahc, SHADDR + 3, data_addr >> 24);
+ ahc_outb(ahc, SHADDR + 2, data_addr >> 16);
+ ahc_outb(ahc, SHADDR + 1, data_addr >> 8);
+ ahc_outb(ahc, SHADDR, data_addr);
+ }
}
}
}
@@ -3895,8 +4228,8 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc_set_width(ahc, devinfo, path, MSG_EXT_WDTR_BUS_8_BIT,
AHC_TRANS_CUR, /*paused*/TRUE);
ahc_set_syncrate(ahc, devinfo, path, /*syncrate*/NULL,
- /*period*/0, /*offset*/0, AHC_TRANS_CUR,
- /*paused*/TRUE);
+ /*period*/0, /*offset*/0, /*ppr_options*/0,
+ AHC_TRANS_CUR, /*paused*/TRUE);
if (error == CAM_REQ_CMP && acode != 0)
xpt_async(AC_SENT_BDR, path, NULL);
@@ -3925,6 +4258,16 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
ccb = scb->ccb;
LIST_REMOVE(&ccb->ccb_h, sim_links.le);
+ if (ccb->ccb_h.func_code == XPT_SCSI_IO
+ && ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0
+ || ccb->csio.tag_action == CAM_TAG_ACTION_NONE)
+ && (ahc->features & AHC_SCB_BTT) == 0) {
+ struct scb_tailq *untagged_q;
+
+ untagged_q = &ahc->untagged_queues[ccb->ccb_h.target_id];
+ TAILQ_REMOVE(untagged_q, scb, links.tqe);
+ ahc_run_untagged_queue(ahc, untagged_q);
+ }
untimeout(ahc_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch);
@@ -3939,13 +4282,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
}
- /*
- * Unbusy this target/channel/lun.
- * XXX if we are holding two commands per lun,
- * send the next command.
- */
- ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE);
-
if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
if (ahc_ccb_status(ccb) == CAM_REQ_INPROG)
ccb->ccb_h.status |= CAM_REQ_CMP;
@@ -3983,8 +4319,9 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
* Ensure that we didn't put a second instance of this
* SCB into the QINFIFO.
*/
- ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
- SCB_LUN(scb), scb->hscb->tag,
+ ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+ SCB_GET_CHANNEL(ahc, scb),
+ SCB_GET_LUN(scb), scb->hscb->tag,
ROLE_INITIATOR, /*status*/0,
SEARCH_REMOVE);
if (ahc_ccb_status(ccb) == CAM_BDR_SENT
@@ -4012,7 +4349,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
*/
bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
bcopy(&ahc->scb_data->sense[scb->hscb->tag],
- &ccb->csio.sense_data, scb->sg_list->len);
+ &ccb->csio.sense_data,
+ scb->sg_list->len & AHC_SG_LEN_MASK);
scb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
}
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
@@ -4054,7 +4392,7 @@ ahc_init(struct ahc_softc *ahc)
u_int discenable;
u_int tagenable;
size_t driver_data_size;
- u_int32_t physaddr;
+ uint32_t physaddr;
#ifdef AHC_PRINT_SRAM
printf("Scratch Ram:");
@@ -4121,13 +4459,13 @@ ahc_init(struct ahc_softc *ahc)
/*
* DMA tag for our command fifos and other data in system memory
* the card's sequencer must be able to access. For initiator
- * roles, we need to allocate space for the qinfifo, qoutfifo,
- * and untagged_scb arrays each of which are composed of 256
- * 1 byte elements. When providing for the target mode role,
- * we additionally must provide space for the incoming target
- * command fifo.
+ * roles, we need to allocate space for the the qinfifo and qoutfifo.
+ * The qinfifo and qoutfifo are composed of 256 1 byte elements.
+ * When providing for the target mode role, we additionally must
+ * provide space for the incoming target command fifo and an extra
+ * byte to deal with a dma bug in some chip versions.
*/
- driver_data_size = 3 * 256 * sizeof(u_int8_t);
+ driver_data_size = 2 * 256 * sizeof(uint8_t);
if ((ahc->flags & AHC_TARGETMODE) != 0)
driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd)
+ /*DMA WideOdd Bug Buffer*/1;
@@ -4145,7 +4483,8 @@ ahc_init(struct ahc_softc *ahc)
ahc->init_level++;
/* Allocation of driver data */
- if (bus_dmamem_alloc(ahc->shared_data_dmat, (void **)&ahc->qoutfifo,
+ if (bus_dmamem_alloc(ahc->shared_data_dmat,
+ (void **)&ahc->qoutfifo,
BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) {
return (ENOMEM);
}
@@ -4154,8 +4493,23 @@ ahc_init(struct ahc_softc *ahc)
/* And permanently map it in */
bus_dmamap_load(ahc->shared_data_dmat, ahc->shared_data_dmamap,
- ahc->qoutfifo, driver_data_size,
- ahcdmamapcb, &ahc->shared_data_busaddr, /*flags*/0);
+ ahc->qoutfifo, driver_data_size, ahcdmamapcb,
+ &ahc->shared_data_busaddr, /*flags*/0);
+
+ if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo;
+ ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
+ ahc->dma_bug_buf = ahc->shared_data_busaddr
+ + driver_data_size - 1;
+ /* All target command blocks start out invalid. */
+ for (i = 0; i < AHC_TMODE_CMDS; i++)
+ ahc->targetcmds[i].cmd_valid = 0;
+ ahc->tqinfifonext = 1;
+ ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
+ ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+ ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
+ }
+ ahc->qinfifo = &ahc->qoutfifo[256];
ahc->init_level++;
@@ -4164,34 +4518,23 @@ ahc_init(struct ahc_softc *ahc)
if (ahcinitscbdata(ahc) != 0)
return (ENOMEM);
- ahc->qinfifo = &ahc->qoutfifo[256];
- ahc->untagged_scbs = &ahc->qinfifo[256];
/* There are no untagged SCBs active yet. */
- for (i = 0; i < 256; i++)
- ahc->untagged_scbs[i] = SCB_LIST_NULL;
+ /* XXX will need to change for SCB ram approach */
+ for (i = 0; i < 16; i++)
+ ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0), /*unbusy*/TRUE);
/* All of our queues are empty */
for (i = 0; i < 256; i++)
ahc->qoutfifo[i] = SCB_LIST_NULL;
+ for (i = 0; i < 256; i++)
+ ahc->qinfifo[i] = SCB_LIST_NULL;
+
if ((ahc->features & AHC_MULTI_TID) != 0) {
ahc_outb(ahc, TARGID, 0);
ahc_outb(ahc, TARGID + 1, 0);
}
- if ((ahc->flags & AHC_TARGETMODE) != 0) {
-
- ahc->targetcmds = (struct target_cmd *)&ahc->untagged_scbs[256];
- ahc->dma_bug_buf = ahc->shared_data_busaddr
- + driver_data_size - 1;
- /* All target command blocks start out invalid. */
- for (i = 0; i < AHC_TMODE_CMDS; i++)
- ahc->targetcmds[i].cmd_valid = 0;
- ahc->tqinfifonext = 1;
- ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
- ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
- }
-
/*
* Allocate a tstate to house information for our
* initiator presence on the bus as well as the user
@@ -4341,7 +4684,7 @@ ahc_init(struct ahc_softc *ahc)
tinfo->user.offset = ~0;
} else {
u_int scsirate;
- u_int16_t mask;
+ uint16_t mask;
/* Take the settings leftover in scratch RAM. */
scsirate = ahc_inb(ahc, TARG_SCSIRATE + i);
@@ -4371,6 +4714,10 @@ ahc_init(struct ahc_softc *ahc)
tinfo->user.period = 0;
else
tinfo->user.offset = ~0;
+ if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/
+ && (ahc->features & AHC_DT) != 0)
+ tinfo->user.ppr_options =
+ MSG_EXT_PPR_DT_REQ;
} else if ((scsirate & SOFS) != 0) {
tinfo->user.period =
ahc_find_period(ahc, scsirate,
@@ -4383,6 +4730,15 @@ ahc_init(struct ahc_softc *ahc)
if ((scsirate & WIDEXFER) != 0
&& (ahc->features & AHC_WIDE) != 0)
tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+ tinfo->user.protocol_version = 4;
+ if ((ahc->features & AHC_DT) != 0)
+ tinfo->user.transport_version = 3;
+ else
+ tinfo->user.transport_version = 2;
+ tinfo->goal.protocol_version = 2;
+ tinfo->goal.transport_version = 2;
+ tinfo->current.protocol_version = 2;
+ tinfo->current.transport_version = 2;
}
tstate->ultraenb = ultraenb;
tstate->discenable = discenable;
@@ -4401,17 +4757,10 @@ ahc_init(struct ahc_softc *ahc)
ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
physaddr = ahc->shared_data_busaddr;
- ahc_outb(ahc, SCBID_ADDR, physaddr & 0xFF);
- ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF);
- ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF);
- ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF);
-
- /* Target mode incomding command fifo */
- physaddr += 3 * 256 * sizeof(u_int8_t);
- ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF);
- ahc_outb(ahc, TMODE_CMDADDR + 1, (physaddr >> 8) & 0xFF);
- ahc_outb(ahc, TMODE_CMDADDR + 2, (physaddr >> 16) & 0xFF);
- ahc_outb(ahc, TMODE_CMDADDR + 3, (physaddr >> 24) & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
/*
* Initialize the group code to command length table.
@@ -4481,6 +4830,24 @@ ahc_init(struct ahc_softc *ahc)
EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
ahc, SHUTDOWN_PRI_DEFAULT);
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ int wait;
+
+ /*
+ * Wait for up to 500ms for our transceivers
+ * to settle. If the adapter does not have
+ * a cable attached, the tranceivers may
+ * never settle, so don't complain if we
+ * fail here.
+ */
+ pause_sequencer(ahc);
+ for (wait = 5000;
+ (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+ wait--)
+ DELAY(100);
+ unpause_sequencer(ahc);
+ }
+
return (0);
}
@@ -4489,7 +4856,7 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb,
struct tmode_tstate **tstate, struct tmode_lstate **lstate,
int notfound_failure)
{
- int our_id;
+ u_int our_id;
/*
* If we are not configured for target mode, someone
@@ -4628,7 +4995,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
struct hardware_scb *hscb;
struct ahc_initiator_tinfo *tinfo;
struct tmode_tstate *tstate;
- u_int16_t mask;
+ uint16_t mask;
/*
* get an scb to use.
@@ -4659,11 +5026,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
/*
* Put all the arguments for the xfer in the scb
*/
- hscb->tcl = ((target_id << 4) & 0xF0)
- | (SIM_IS_SCSIBUS_B(ahc, sim) ? SELBUSB : 0)
- | (ccb->ccb_h.target_lun & 0x07);
-
- mask = SCB_TARGET_MASK(scb);
+ hscb->control = 0;
+ hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id);
+ hscb->lun = ccb->ccb_h.target_lun;
+ mask = SCB_GET_TARGET_MASK(ahc, scb);
tinfo = ahc_fetch_transinfo(ahc, SIM_CHANNEL(ahc, sim), our_id,
target_id, &tstate);
@@ -4675,33 +5041,35 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
if ((tstate->discenable & mask) != 0
&& (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0)
hscb->control |= DISCENB;
-
+
+ if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
+ && (tinfo->current.width != 0 || tinfo->current.period != 0)) {
+ scb->flags |= SCB_NEGOTIATE;
+ hscb->control |= MK_MESSAGE;
+ }
+
if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
- hscb->cmdpointer = NULL;
+ hscb->cdb_len = 0;
scb->flags |= SCB_DEVICE_RESET;
hscb->control |= MK_MESSAGE;
ahc_execute_scb(scb, NULL, 0, 0);
} else {
if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
+ struct target_data *tdata;
+
+ tdata = &hscb->shared_data.tdata;
if (ahc->pending_device == lstate) {
scb->flags |= SCB_TARGET_IMMEDIATE;
ahc->pending_device = NULL;
}
hscb->control |= TARGET_SCB;
- hscb->cmdpointer = IDENTIFY_SEEN;
+ tdata->target_phases = IDENTIFY_SEEN;
if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
- hscb->cmdpointer |= SPHASE_PENDING;
- hscb->status = ccb->csio.scsi_status;
+ tdata->target_phases |= SPHASE_PENDING;
+ tdata->scsi_status =
+ ccb->csio.scsi_status;
}
-
- /* Overloaded with tag ID */
- hscb->cmdlen = ccb->csio.tag_id;
- /*
- * Overloaded with the value to place
- * in SCSIID for reselection.
- */
- hscb->cmdpointer |=
- (our_id|(hscb->tcl & 0xF0)) << 16;
+ tdata->initiator_tag = ccb->csio.tag_id;
}
if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID)
hscb->control |= ccb->csio.tag_action;
@@ -4742,14 +5110,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
}
case XPT_SET_TRAN_SETTINGS:
{
- struct ahc_devinfo devinfo;
- struct ccb_trans_settings *cts;
- struct ahc_initiator_tinfo *tinfo;
- struct tmode_tstate *tstate;
- u_int16_t *discenable;
- u_int16_t *tagenable;
- u_int update_type;
- int s;
+ struct ahc_devinfo devinfo;
+ struct ccb_trans_settings *cts;
+ struct ahc_initiator_tinfo *tinfo;
+ struct tmode_tstate *tstate;
+ uint16_t *discenable;
+ uint16_t *tagenable;
+ u_int update_type;
+ int s;
cts = &ccb->cts;
ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
@@ -4792,62 +5160,69 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
}
if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
- switch (cts->bus_width) {
- case MSG_EXT_WDTR_BUS_16_BIT:
- if ((ahc->features & AHC_WIDE) != 0)
- break;
- /* FALLTHROUGH to 8bit */
- case MSG_EXT_WDTR_BUS_32_BIT:
- case MSG_EXT_WDTR_BUS_8_BIT:
- default:
- cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- }
+ ahc_validate_width(ahc, &cts->bus_width);
ahc_set_width(ahc, &devinfo, cts->ccb_h.path,
cts->bus_width, update_type,
/*paused*/FALSE);
}
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) {
+ if (update_type == AHC_TRANS_USER)
+ cts->sync_offset = tinfo->user.offset;
+ else
+ cts->sync_offset = tinfo->goal.offset;
+ }
+
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) {
+ if (update_type == AHC_TRANS_USER)
+ cts->sync_period = tinfo->user.period;
+ else
+ cts->sync_period = tinfo->goal.period;
+ }
+
if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
|| ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
struct ahc_syncrate *syncrate;
+ u_int ppr_options;
u_int maxsync;
if ((ahc->features & AHC_ULTRA2) != 0)
- maxsync = AHC_SYNCRATE_ULTRA2;
+ maxsync = AHC_SYNCRATE_DT;
else if ((ahc->features & AHC_ULTRA) != 0)
maxsync = AHC_SYNCRATE_ULTRA;
else
maxsync = AHC_SYNCRATE_FAST;
- if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) {
- if (update_type & AHC_TRANS_USER)
- cts->sync_offset = tinfo->user.offset;
- else
- cts->sync_offset = tinfo->goal.offset;
- }
-
- if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) {
- if (update_type & AHC_TRANS_USER)
- cts->sync_period = tinfo->user.period;
- else
- cts->sync_period = tinfo->goal.period;
- }
+ ppr_options = 0;
+ if (cts->sync_period <= 9)
+ ppr_options = MSG_EXT_PPR_DT_REQ;
syncrate = ahc_find_syncrate(ahc, &cts->sync_period,
+ &ppr_options,
maxsync);
ahc_validate_offset(ahc, syncrate, &cts->sync_offset,
MSG_EXT_WDTR_BUS_8_BIT);
/* We use a period of 0 to represent async */
- if (cts->sync_offset == 0)
+ if (cts->sync_offset == 0) {
cts->sync_period = 0;
+ ppr_options = 0;
+ }
+ if (ppr_options == MSG_EXT_PPR_DT_REQ
+ && tinfo->user.transport_version >= 3) {
+ tinfo->goal.transport_version =
+ tinfo->user.transport_version;
+ tinfo->current.transport_version =
+ tinfo->user.transport_version;
+ }
+
ahc_set_syncrate(ahc, &devinfo, cts->ccb_h.path,
syncrate, cts->sync_period,
- cts->sync_offset, update_type,
- /*paused*/FALSE);
+ cts->sync_offset, ppr_options,
+ update_type, /*paused*/FALSE);
}
+
splx(s);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
@@ -4881,7 +5256,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
s = splcam();
cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
- if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
if ((ahc->user_discenable & devinfo.target_mask) != 0)
cts->flags |= CCB_TRANS_DISC_ENB;
@@ -4894,7 +5269,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
if ((tstate->tagenable & devinfo.target_mask) != 0)
cts->flags |= CCB_TRANS_TAG_ENB;
}
-
cts->sync_period = tinfo->period;
cts->sync_offset = tinfo->offset;
cts->bus_width = tinfo->width;
@@ -4914,8 +5288,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
case XPT_CALC_GEOMETRY:
{
struct ccb_calc_geometry *ccg;
- u_int32_t size_mb;
- u_int32_t secs_per_cylinder;
+ uint32_t size_mb;
+ uint32_t secs_per_cylinder;
int extended;
ccg = &ccb->ccg;
@@ -4946,7 +5320,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim),
/*initiate reset*/TRUE);
splx(s);
- if (bootverbose) {
+ if (1 || bootverbose) {
xpt_print_path(SIM_PATH(ahc, sim));
printf("SCSI bus reset delivered. "
"%d SCBs aborted.\n", found);
@@ -4979,7 +5353,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
? 0 : PIM_NOINITIATOR;
cpi->hba_eng_cnt = 0;
cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7;
- cpi->max_lun = 7;
+ cpi->max_lun = 64;
if (SIM_IS_SCSIBUS_B(ahc, sim)) {
cpi->initiator_id = ahc->our_id_b;
if ((ahc->flags & AHC_RESET_BUS_B) == 0)
@@ -5007,7 +5381,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
}
static void
-ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
+ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
{
struct ahc_softc *ahc;
struct cam_sim *sim;
@@ -5035,7 +5409,7 @@ ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
AHC_TRANS_GOAL|AHC_TRANS_CUR,
/*paused*/FALSE);
ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL,
- /*period*/0, /*offset*/0,
+ /*period*/0, /*offset*/0, /*ppr_options*/0,
AHC_TRANS_GOAL|AHC_TRANS_CUR,
/*paused*/FALSE);
splx(s);
@@ -5077,21 +5451,23 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
end_seg = dm_segs + nsegments;
- /* Copy the first SG into the data pointer area */
- scb->hscb->data = dm_segs->ds_addr;
- scb->hscb->datalen = dm_segs->ds_len;
-
/* Copy the segments into our SG list */
sg = scb->sg_list;
while (dm_segs < end_seg) {
sg->addr = dm_segs->ds_addr;
+/* XXX Add in the 5th byte of the address later. */
sg->len = dm_segs->ds_len;
sg++;
dm_segs++;
}
-
- /* Note where to find the SG entries in bus space */
- scb->hscb->SG_pointer = scb->sg_list_phys;
+
+ /*
+ * Note where to find the SG entries in bus space.
+ * We also set the full residual flag which the
+ * sequencer will clear as soon as a data transfer
+ * occurs.
+ */
+ scb->hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_PREREAD;
@@ -5101,9 +5477,14 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op);
if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
- scb->hscb->cmdpointer |= DPHASE_PENDING;
- if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
- scb->hscb->cmdpointer |= (TARGET_DATA_IN << 8);
+ struct target_data *tdata;
+
+ tdata = &scb->hscb->shared_data.tdata;
+ tdata->target_phases |= DPHASE_PENDING;
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
+ tdata->data_phase = P_DATAOUT;
+ else
+ tdata->data_phase = P_DATAIN;
/*
* If the transfer is of an odd length and in the
@@ -5115,9 +5496,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
* negotiated wide as negotiation could occur before
* this command is executed.
*/
- if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN
+ if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0
&& (ccb->csio.dxfer_len & 0x1) != 0
- && (ahc->features & AHC_TARG_DMABUG) != 0) {
+ && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
nsegments++;
if (nsegments > AHC_NSEG) {
@@ -5132,15 +5513,22 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
}
sg->addr = ahc->dma_bug_buf;
sg->len = 1;
+ sg++;
}
}
+ sg--;
+ sg->len |= AHC_DMA_LAST_SEG;
+
+ /* Copy the first SG into the "current" data pointer area */
+ scb->hscb->dataptr = scb->sg_list->addr;
+ scb->hscb->datacnt = scb->sg_list->len;
} else {
- scb->hscb->SG_pointer = 0;
- scb->hscb->data = 0;
- scb->hscb->datalen = 0;
+ scb->hscb->sgptr = SG_LIST_NULL;
+ scb->hscb->dataptr = 0;
+ scb->hscb->datacnt = 0;
}
- scb->sg_count = scb->hscb->SG_count = nsegments;
+ scb->sg_count = nsegments;
s = splcam();
@@ -5157,14 +5545,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
return;
}
- /* Busy this tcl if we are untagged */
- if ((scb->hscb->control & TAG_ENB) == 0)
- ahc_busy_tcl(ahc, scb);
-
LIST_INSERT_HEAD(&ahc->pending_ccbs, &ccb->ccb_h,
sim_links.le);
- scb->flags |= SCB_ACTIVE;
ccb->ccb_h.status |= CAM_SIM_QUEUED;
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
@@ -5175,6 +5558,25 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
(ccb->ccb_h.timeout * hz) / 1000);
}
+ /*
+ * We only allow one untagged transaction
+ * per target in the initiator role unless
+ * we are storing a full busy target *lun*
+ * table in SCB space.
+ */
+ if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
+ && (ahc->features & AHC_SCB_BTT) == 0) {
+ struct scb_tailq *untagged_q;
+
+ untagged_q = &(ahc->untagged_queues[ccb->ccb_h.target_id]);
+ TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
+ if (TAILQ_FIRST(untagged_q) != scb) {
+ splx(s);
+ return;
+ }
+ }
+ scb->flags |= SCB_ACTIVE;
+
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
#if 0
printf("Continueing Immediate Command %d:%d\n",
@@ -5187,16 +5589,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
unpause_sequencer(ahc);
} else {
-
- ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
-
- if ((ahc->features & AHC_QUEUE_REGS) != 0) {
- ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
- } else {
- pause_sequencer(ahc);
- ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
- unpause_sequencer(ahc);
- }
+ ahc_queue_scb(ahc, scb);
}
splx(s);
@@ -5219,33 +5612,42 @@ ahc_setup_data(struct ahc_softc *ahc, struct ccb_scsiio *csio,
ccb_h = &csio->ccb_h;
if (ccb_h->func_code == XPT_SCSI_IO) {
- hscb->cmdlen = csio->cdb_len;
+ hscb->cdb_len = csio->cdb_len;
if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
- if ((ccb_h->flags & CAM_CDB_PHYS) == 0)
- if (hscb->cmdlen <= 16) {
- memcpy(hscb->cmdstore,
- csio->cdb_io.cdb_ptr,
- hscb->cmdlen);
- hscb->cmdpointer =
- hscb->cmdstore_busaddr;
- } else {
- ahcsetccbstatus(scb->ccb,
- CAM_REQ_INVALID);
- xpt_done(scb->ccb);
- ahcfreescb(ahc, scb);
- return;
+
+ if (hscb->cdb_len > sizeof(hscb->cdb32)
+ || (ccb_h->flags & CAM_CDB_PHYS) != 0) {
+ ahcsetccbstatus(scb->ccb, CAM_REQ_INVALID);
+ xpt_done(scb->ccb);
+ ahcfreescb(ahc, scb);
+ return;
+ }
+ if (hscb->cdb_len > 12) {
+ memcpy(hscb->cdb32,
+ csio->cdb_io.cdb_ptr,
+ hscb->cdb_len);
+ if ((ahc->flags & AHC_CMD_CHAN) == 0) {
+ hscb->shared_data.cdb_ptr =
+ scb->cdb32_busaddr;
}
- else
- hscb->cmdpointer =
- ((intptr_t)csio->cdb_io.cdb_ptr) & 0xffffffff;
+ } else {
+ memcpy(hscb->shared_data.cdb,
+ csio->cdb_io.cdb_ptr,
+ hscb->cdb_len);
+ }
} else {
- /*
- * CCB CDB Data Storage area is only 16 bytes
- * so no additional testing is required
- */
- memcpy(hscb->cmdstore, csio->cdb_io.cdb_bytes,
- hscb->cmdlen);
- hscb->cmdpointer = hscb->cmdstore_busaddr;
+ if (hscb->cdb_len > 12) {
+ memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes,
+ hscb->cdb_len);
+ if ((ahc->flags & AHC_CMD_CHAN) == 0) {
+ hscb->shared_data.cdb_ptr =
+ scb->cdb32_busaddr;
+ }
+ } else {
+ memcpy(hscb->shared_data.cdb,
+ csio->cdb_io.cdb_bytes,
+ hscb->cdb_len);
+ }
}
}
@@ -5381,10 +5783,11 @@ ahcallocscbs(struct ahc_softc *ahc)
break;
next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
next_scb->hscb->tag = ahc->scb_data->numscbs;
- next_scb->hscb->cmdstore_busaddr =
+ next_scb->cdb32_busaddr =
ahc_hscb_busaddr(ahc, next_scb->hscb->tag)
- + offsetof(struct hardware_scb, cmdstore);
- SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links);
+ + offsetof(struct hardware_scb, cdb32);
+ SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
+ next_scb, links.sle);
segs += AHC_NSEG;
physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg));
next_scb++;
@@ -5410,7 +5813,7 @@ ahc_dumpseq(struct ahc_softc* ahc)
ahc_outb(ahc, SEQADDR0, 0);
ahc_outb(ahc, SEQADDR1, 0);
for (i = 0; i < max_prog; i++) {
- u_int8_t ins_bytes[4];
+ uint8_t ins_bytes[4];
ahc_insb(ahc, SEQRAM, ins_bytes, 4);
printf("0x%08x\n", ins_bytes[0] << 24
@@ -5425,16 +5828,16 @@ static void
ahc_loadseq(struct ahc_softc *ahc)
{
struct patch *cur_patch;
- int i;
+ u_int i;
int downloaded;
- int skip_addr;
- u_int8_t download_consts[4];
+ u_int skip_addr;
+ uint8_t download_consts[2];
/* Setup downloadable constant table */
-#if 0
- /* No downloaded constants are currently defined. */
- download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds;
-#endif
+ download_consts[QOUTFIFO_OFFSET] = 0;
+ if (ahc->targetcmds != NULL)
+ download_consts[QOUTFIFO_OFFSET] += 32;
+ download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1;
cur_patch = patches;
downloaded = 0;
@@ -5463,11 +5866,11 @@ ahc_loadseq(struct ahc_softc *ahc)
static int
ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
- int start_instr, int *skip_addr)
+ u_int start_instr, u_int *skip_addr)
{
struct patch *cur_patch;
struct patch *last_patch;
- int num_patches;
+ u_int num_patches;
num_patches = sizeof(patches)/sizeof(struct patch);
last_patch = &patches[num_patches];
@@ -5498,7 +5901,7 @@ ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
}
static void
-ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)
+ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
{
union ins_formats instr;
struct ins_format1 *fmt1_ins;
@@ -5508,6 +5911,15 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)
/* Structure copy */
instr = *(union ins_formats*)&seqprog[instrptr * 4];
+#if BYTE_ORDER == BIG_ENDIAN
+ opcode = instr.format.bytes[0];
+ instr.format.bytes[0] = instr.format.bytes[3];
+ instr.format.bytes[3] = opcode;
+ opcode = instr.format.bytes[1];
+ instr.format.bytes[1] = instr.format.bytes[2];
+ instr.format.bytes[2] = opcode;
+#endif
+
fmt1_ins = &instr.format1;
fmt3_ins = NULL;
@@ -5526,8 +5938,8 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)
struct patch *cur_patch;
int address_offset;
u_int address;
- int skip_addr;
- int i;
+ u_int skip_addr;
+ u_int i;
fmt3_ins = &instr.format3;
address_offset = 0;
@@ -5570,7 +5982,7 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)
/* Calculate odd parity for the instruction */
for (i = 0, count = 0; i < 31; i++) {
- u_int32_t mask;
+ uint32_t mask;
mask = 0x01 << i;
if ((instr.integer & mask) != 0)
@@ -5595,6 +6007,14 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)
| (fmt1_ins->opcode << 25);
}
}
+#if BYTE_ORDER == BIG_ENDIAN
+ opcode = instr.format.bytes[0];
+ instr.format.bytes[0] = instr.format.bytes[3];
+ instr.format.bytes[3] = opcode;
+ opcode = instr.format.bytes[1];
+ instr.format.bytes[1] = instr.format.bytes[2];
+ instr.format.bytes[2] = opcode;
+#endif
ahc_outsb(ahc, SEQRAM, instr.bytes, 4);
break;
default:
@@ -5665,19 +6085,20 @@ ahc_timeout(void *arg)
pause_sequencer(ahc);
} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
+ xpt_print_path(scb->ccb->ccb_h.path);
if ((scb->flags & SCB_ACTIVE) == 0) {
/* Previous timeout took care of me already */
- printf("Timedout SCB handled by another timeout\n");
+ printf("Timedout SCB %d handled by another timeout\n",
+ scb->hscb->tag);
unpause_sequencer(ahc);
splx(s);
return;
}
- target = SCB_TARGET(scb);
- channel = SCB_CHANNEL(scb);
- lun = SCB_LUN(scb);
+ target = SCB_GET_TARGET(ahc, scb);
+ channel = SCB_GET_CHANNEL(ahc, scb);
+ lun = SCB_GET_LUN(scb);
- xpt_print_path(scb->ccb->ccb_h.path);
printf("SCB 0x%x - timed out ", scb->hscb->tag);
/*
* Take a snapshot of the bus state and print out
@@ -5771,7 +6192,8 @@ bus_reset:
* taking additional action.
*/
active_scb = &ahc->scb_data->scbarray[active_scb_index];
- if (active_scb->hscb->tcl != scb->hscb->tcl) {
+ if (active_scb->hscb->scsiid != scb->hscb->scsiid
+ || active_scb->hscb->lun != scb->hscb->lun) {
struct ccb_hdr *ccbh;
u_int newtimeout;
@@ -5871,8 +6293,6 @@ bus_reset:
ahc_outb(ahc, SCB_CONTROL, scb_control);
}
ahc_outb(ahc, SCBPTR, active_scb);
- ahc_index_busy_tcl(ahc, scb->hscb->tcl,
- /*unbusy*/TRUE);
/*
* Actually re-queue this SCB in case we can
@@ -5881,8 +6301,9 @@ bus_reset:
* so we are the next SCB for this target
* to run.
*/
- ahc_search_qinfifo(ahc, SCB_TARGET(scb),
- channel, SCB_LUN(scb),
+ ahc_search_qinfifo(ahc,
+ SCB_GET_TARGET(ahc, scb),
+ channel, SCB_GET_LUN(scb),
SCB_LIST_NULL,
ROLE_INITIATOR,
CAM_REQUEUE_REQ,
@@ -5918,18 +6339,28 @@ bus_reset:
static int
ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
- int lun, u_int tag, role_t role, u_int32_t status,
+ int lun, u_int tag, role_t role, uint32_t status,
ahc_search_action action)
{
struct scb *scbp;
- u_int8_t qinpos;
- u_int8_t qintail;
+ uint8_t qinpos;
+ uint8_t qintail;
+ uint8_t next, prev;
+ uint8_t curscbptr;
int found;
qinpos = ahc_inb(ahc, QINPOS);
qintail = ahc->qinfifonext;
found = 0;
+ if (action == SEARCH_COMPLETE) {
+ /*
+ * Don't attempt to run any queued untagged transactions
+ * until we are done with the abort process.
+ */
+ ahc_freeze_untagged_queues(ahc);
+ }
+
/*
* Start with an empty queue. Entries that are not chosen
* for removal will be re-added to the queue as we go.
@@ -5938,10 +6369,11 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
while (qinpos != qintail) {
scbp = &ahc->scb_data->scbarray[ahc->qinfifo[qinpos]];
- if (ahc_match_scb(scbp, target, channel, lun, tag, role)) {
+ if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) {
/*
- * We found an scb that needs to be removed.
+ * We found an scb that needs to be acted on.
*/
+ found++;
switch (action) {
case SEARCH_COMPLETE:
if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG)
@@ -5956,7 +6388,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
case SEARCH_REMOVE:
break;
}
- found++;
} else {
ahc->qinfifo[ahc->qinfifonext++] = scbp->hscb->tag;
}
@@ -5969,6 +6400,56 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
}
+ /*
+ * Search waiting for selection list.
+ */
+ curscbptr = ahc_inb(ahc, SCBPTR);
+ next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */
+ prev = SCB_LIST_NULL;
+
+ while (next != SCB_LIST_NULL) {
+ uint8_t scb_index;
+
+ ahc_outb(ahc, SCBPTR, next);
+ scb_index = ahc_inb(ahc, SCB_TAG);
+ if (scb_index >= ahc->scb_data->numscbs) {
+ panic("Waiting List inconsistency. "
+ "SCB index == %d, yet numscbs == %d.",
+ scb_index, ahc->scb_data->numscbs);
+ }
+ scbp = &ahc->scb_data->scbarray[scb_index];
+ if (ahc_match_scb(ahc, scbp, target, channel,
+ lun, SCB_LIST_NULL, role)) {
+ /*
+ * We found an scb that needs to be acted on.
+ */
+ found++;
+ switch (action) {
+ case SEARCH_REMOVE:
+ next = ahc_rem_wscb(ahc, next, prev);
+ break;
+ case SEARCH_COMPLETE:
+ next = ahc_rem_wscb(ahc, next, prev);
+ if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG)
+ ahcsetccbstatus(scbp->ccb, status);
+ ahc_freeze_ccb(scbp->ccb);
+ ahc_done(ahc, scbp);
+ break;
+ case SEARCH_COUNT:
+ prev = next;
+ next = ahc_inb(ahc, SCB_NEXT);
+ break;
+ }
+ } else {
+
+ prev = next;
+ next = ahc_inb(ahc, SCB_NEXT);
+ }
+ }
+ ahc_outb(ahc, SCBPTR, curscbptr);
+
+ if (action == SEARCH_COMPLETE)
+ ahc_release_untagged_queues(ahc);
return (found);
}
@@ -6063,13 +6544,20 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
*/
static int
ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
- int lun, u_int tag, role_t role, u_int32_t status)
+ int lun, u_int tag, role_t role, uint32_t status)
{
struct scb *scbp;
u_int active_scb;
int i;
+ int maxtarget;
int found;
+ /*
+ * Don't attempt to run any queued untagged transactions
+ * until we are done with the abort process.
+ */
+ ahc_freeze_untagged_queues(ahc);
+
/* restore this when we're done */
active_scb = ahc_inb(ahc, SCBPTR);
@@ -6077,36 +6565,28 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
/*
- * Search waiting for selection list.
+ * Clean out the busy target table for any untagged commands.
*/
- {
- u_int8_t next, prev;
-
- next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */
- prev = SCB_LIST_NULL;
-
- while (next != SCB_LIST_NULL) {
- u_int8_t scb_index;
+ i = 0;
+ maxtarget = 16;
+ if (target != CAM_TARGET_WILDCARD) {
+ i = target;
+ maxtarget = target + 1;
+ }
- ahc_outb(ahc, SCBPTR, next);
- scb_index = ahc_inb(ahc, SCB_TAG);
- if (scb_index >= ahc->scb_data->numscbs) {
- panic("Waiting List inconsistency. "
- "SCB index == %d, yet numscbs == %d.",
- scb_index, ahc->scb_data->numscbs);
- }
- scbp = &ahc->scb_data->scbarray[scb_index];
- if (ahc_match_scb(scbp, target, channel,
- lun, SCB_LIST_NULL, role)) {
+ for (;i < maxtarget; i++) {
+ u_int scbid;
- next = ahc_abort_wscb(ahc, next, prev);
- } else {
-
- prev = next;
- next = ahc_inb(ahc, SCB_NEXT);
- }
- }
+ /* XXX Will need lun loop for SCB ram version */
+ scbid = ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0),
+ /*unbusy*/FALSE);
+ scbp = &ahc->scb_data->scbarray[scbid];
+ if (scbid < ahc->scb_data->numscbs
+ && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))
+ ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0),
+ /*unbusy*/TRUE);
}
+
/*
* Go through the disconnected list and remove any entries we
* have queued for completion, 0'ing their control byte too.
@@ -6128,7 +6608,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
scbid = ahc_inb(ahc, SCB_TAG);
scbp = &ahc->scb_data->scbarray[scbid];
if (scbid < ahc->scb_data->numscbs
- && ahc_match_scb(scbp, target, channel, lun, tag, role))
+ && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))
ahc_add_curscb_to_free_list(ahc);
}
@@ -6145,7 +6625,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
while (ccb_h != NULL) {
scbp = (struct scb *)ccb_h->ccb_scb_ptr;
ccb_h = ccb_h->sim_links.le.le_next;
- if (ahc_match_scb(scbp, target, channel,
+ if (ahc_match_scb(ahc, scbp, target, channel,
lun, tag, role)) {
if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG)
ahcsetccbstatus(scbp->ccb, status);
@@ -6156,6 +6636,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
}
}
ahc_outb(ahc, SCBPTR, active_scb);
+ ahc_release_untagged_queues(ahc);
return found;
}
@@ -6191,8 +6672,14 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel,
"SCB index == %d, yet numscbs == %d.",
scb_index, ahc->scb_data->numscbs);
}
+
+ if (next == prev) {
+ panic("Disconnected List Loop. "
+ "cur SCBPTR == %x, prev SCBPTR == %x.",
+ next, prev);
+ }
scbp = &ahc->scb_data->scbarray[scb_index];
- if (ahc_match_scb(scbp, target, channel, lun,
+ if (ahc_match_scb(ahc, scbp, target, channel, lun,
tag, ROLE_INITIATOR)) {
count++;
if (remove) {
@@ -6250,7 +6737,7 @@ ahc_add_curscb_to_free_list(struct ahc_softc *ahc)
* scb that follows the one that we remove.
*/
static u_int
-ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
+ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
{
u_int curscb, next;
@@ -6307,7 +6794,7 @@ ahc_clear_intstat(struct ahc_softc *ahc)
static void
ahc_reset_current_bus(struct ahc_softc *ahc)
{
- u_int8_t scsiseq;
+ uint8_t scsiseq;
ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST);
scsiseq = ahc_inb(ahc, SCSISEQ);
@@ -6466,8 +6953,8 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
AHC_TRANS_CUR, /*paused*/TRUE);
ahc_set_syncrate(ahc, &devinfo, path,
/*syncrate*/NULL, /*period*/0,
- /*offset*/0, AHC_TRANS_CUR,
- /*paused*/TRUE);
+ /*offset*/0, /*ppr_options*/0,
+ AHC_TRANS_CUR, /*paused*/TRUE);
}
}
@@ -6479,12 +6966,12 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
}
static int
-ahc_match_scb(struct scb *scb, int target, char channel,
- int lun, u_int tag, role_t role)
+ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
+ char channel, int lun, u_int tag, role_t role)
{
- int targ = SCB_TARGET(scb);
- char chan = SCB_CHANNEL(scb);
- int slun = SCB_LUN(scb);
+ int targ = SCB_GET_TARGET(ahc, scb);
+ char chan = SCB_GET_CHANNEL(ahc, scb);
+ int slun = SCB_GET_LUN(scb);
int match;
match = ((chan == channel) || (channel == ALL_CHANNELS));
@@ -6532,64 +7019,93 @@ ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width)
}
static void
-ahc_calc_residual(struct scb *scb)
+ahc_construct_ppr(struct ahc_softc *ahc, u_int period, u_int offset,
+ u_int bus_width, u_int ppr_options)
{
- struct hardware_scb *hscb;
+ ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+ ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
+ ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
+ ahc->msgout_buf[ahc->msgout_index++] = period;
+ ahc->msgout_buf[ahc->msgout_index++] = 0;
+ ahc->msgout_buf[ahc->msgout_index++] = offset;
+ ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+ ahc->msgout_buf[ahc->msgout_index++] = ppr_options;
+ ahc->msgout_len += 8;
+}
- hscb = scb->hscb;
+static void
+ahc_calc_residual(struct scb *scb)
+{
+ struct hardware_scb *hscb;
+ struct status_pkt *spkt;
+ uint32_t resid;
/*
- * If the disconnected flag is still set, this is bogus
- * residual information left over from a sequencer
- * pagin/pageout, so ignore this case.
+ * 4 cases.
+ * 1) No residual.
+ * SG_RESID_VALID clear in sgptr.
+ * 2) Transferless command
+ * 3) Never performed any transfers.
+ * sgptr has SG_FULL_RESID set.
+ * 4) We have a partial residual.
+ * Use residual_sgptr to determine
+ * where we are.
*/
- if ((scb->hscb->control & DISCONNECTED) == 0) {
- u_int32_t resid;
- int resid_sgs;
- int sg;
-
+
+ /* Cases 1, 2 & 3 are easy. Check them first. */
+ hscb = scb->hscb;
+ if ((hscb->sgptr & SG_RESID_VALID) == 0)
+ return;
+ hscb->sgptr &= ~SG_RESID_VALID;
+
+ if ((hscb->sgptr & SG_LIST_NULL) != 0)
+ return;
+
+ spkt = &hscb->shared_data.status;
+ if ((hscb->sgptr & SG_FULL_RESID) != 0)
+ resid = scb->ccb->csio.dxfer_len;
+ else if ((hscb->sgptr & ~SG_PTR_MASK) != 0)
+ panic("Bogus sgptr value 0x%x\n", hscb->sgptr);
+ else if ((spkt->residual_sg_ptr & ~SG_PTR_MASK) != 0)
+ panic("Bogus resid sgptr value 0x%x\n", spkt->residual_sg_ptr);
+ else {
+ struct ahc_dma_seg *sg;
+
/*
* Remainder of the SG where the transfer
- * stopped.
+ * stopped.
*/
- resid = (hscb->residual_data_count[2] << 16)
- | (hscb->residual_data_count[1] <<8)
- | (hscb->residual_data_count[0]);
+ resid = spkt->residual_datacnt & AHC_SG_LEN_MASK;
+ sg = ahc_sg_bus_to_virt(scb,
+ spkt->residual_sg_ptr & SG_PTR_MASK);
+
+ /* The residual sg_ptr always points to the next sg */
+ sg--;
/*
* Add up the contents of all residual
* SG segments that are after the SG where
* the transfer stopped.
*/
- resid_sgs = scb->hscb->residual_SG_count - 1/*current*/;
- sg = scb->sg_count - resid_sgs;
- while (resid_sgs > 0) {
-
- resid += scb->sg_list[sg].len;
+ while ((sg->len & AHC_DMA_LAST_SEG) == 0) {
sg++;
- resid_sgs--;
+ resid += sg->len & AHC_SG_LEN_MASK;
}
- if ((scb->flags & SCB_SENSE) == 0) {
+ }
+ if ((scb->flags & SCB_SENSE) == 0) {
- scb->ccb->csio.resid = resid;
- } else {
+ scb->ccb->csio.resid = resid;
+ } else {
- scb->ccb->csio.sense_resid = resid;
- }
+ scb->ccb->csio.sense_resid = resid;
+ }
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWMISC) {
- xpt_print_path(scb->ccb->ccb_h.path);
- printf("Handled Residual of %d bytes\n", resid);
- }
-#endif
+ if (ahc_debug & AHC_SHOWMISC) {
+ xpt_print_path(scb->ccb->ccb_h.path);
+ printf("Handled Residual of %d bytes\n", resid);
}
-
- /*
- * Clean out the residual information in this SCB for its
- * next consumer.
- */
- hscb->residual_SG_count = 0;
+#endif
}
static void
@@ -6622,13 +7138,13 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc)
our_id = ccb->ccb_h.target_id;
remote_id = ccb->ctio.init_id;
} else {
- our_id = SCB_IS_SCSIBUS_B(pending_scb)
+ our_id = SCB_IS_SCSIBUS_B(ahc, pending_scb)
? ahc->our_id_b : ahc->our_id;
remote_id = ccb->ccb_h.target_id;
}
ahc_compile_devinfo(&devinfo, our_id, remote_id,
- SCB_LUN(pending_scb),
- SCB_CHANNEL(pending_scb),
+ SCB_GET_LUN(pending_scb),
+ SCB_GET_CHANNEL(ahc, pending_scb),
ROLE_UNKNOWN);
tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
our_id, remote_id, &tstate);
@@ -6670,13 +7186,13 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc)
our_id = ccb->ccb_h.target_id;
remote_id = ccb->ctio.init_id;
} else {
- our_id = SCB_IS_SCSIBUS_B(pending_scb)
+ our_id = SCB_IS_SCSIBUS_B(ahc, pending_scb)
? ahc->our_id_b : ahc->our_id;
remote_id = ccb->ccb_h.target_id;
}
ahc_compile_devinfo(&devinfo, our_id, remote_id,
- SCB_LUN(pending_scb),
- SCB_CHANNEL(pending_scb),
+ SCB_GET_LUN(pending_scb),
+ SCB_GET_CHANNEL(ahc, pending_scb),
ROLE_UNKNOWN);
tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
our_id, remote_id, &tstate);
@@ -6696,8 +7212,8 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc)
static void
ahc_dump_targcmd(struct target_cmd *cmd)
{
- u_int8_t *byte;
- u_int8_t *last_byte;
+ uint8_t *byte;
+ uint8_t *last_byte;
int i;
byte = &cmd->initiator_channel;
diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h
index 3ef8ef8..e491e22 100644
--- a/sys/dev/aic7xxx/aic7xxx.h
+++ b/sys/dev/aic7xxx/aic7xxx.h
@@ -16,7 +16,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,6 +37,7 @@
#define _AIC7XXX_H_
#include "opt_aic7xxx.h" /* for config options */
+#include "aic7xxx_reg.h"
#include <sys/bus.h> /* For device_t */
@@ -49,20 +50,37 @@
#endif
/*
+ * The maximum number of supported targets.
+ */
+#define AHC_NUM_TARGETS 16
+
+/*
+ * 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.
+ */
+#define AHC_NUM_LUNS 256
+
+/*
* The maximum transfer per S/G segment.
*/
#define AHC_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */
/*
- * The number of dma segments supported. The current implementation limits
- * us to 255 S/G entries (this may change to be unlimited at some point).
- * To reduce the driver's memory consumption, we further limit the number
- * supported to be sufficient to handle the largest mapping supported by
- * the kernel, MAXPHYS. Assuming the transfer is as fragmented as possible
- * and unaligned, this turns out to be the number of paged sized transfers
- * in MAXPHYS plus an extra element to handle any unaligned residual.
+ * The number of dma segments supported. The sequencer can handle any number
+ * of physically contiguous S/G entrys. To reduce the driver's memory
+ * consumption, we limit the number supported to be sufficient to handle
+ * the largest mapping supported by the kernel, MAXPHYS. Assuming the
+ * transfer is as fragmented as possible and unaligned, this turns out to
+ * be the number of paged sized transfers in MAXPHYS plus an extra element
+ * to handle any unaligned residual. The sequencer fetches SG elements
+ * in 128 byte chucks, so make the number per-transaction a nice multiple
+ * of 16 (8 byte S/G elements).
*/
-#define AHC_NSEG (MIN(btoc(MAXPHYS) + 1, 255))
+/* XXX Worth the space??? */
+#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
#define AHC_SCB_MAX 255 /*
* Up to 255 SCBs on some types of aic7xxx
@@ -79,11 +97,23 @@
* wrap point of an 8bit counter.
*/
+/*
+ * The aic7xxx chips only support a 24bit length. We use the top
+ * byte of the length to store additional address bits as well
+ * as an indicator if this is the last SG segment in a transfer.
+ * This gives us an addressable range of 512GB on machines with
+ * 64bit PCI or with chips that can support dual address cycles
+ * on 32bit PCI busses.
+ */
struct ahc_dma_seg {
- u_int32_t addr;
- u_int32_t len;
+ uint32_t addr;
+ uint32_t len;
+#define AHC_DMA_LAST_SEG 0x80000000
+#define AHC_SG_HIGH_ADDR_MASK 0x7F000000
+#define AHC_SG_LEN_MASK 0x00FFFFFF
};
+/* The chip order is from least sophisticated to most sophisticated */
typedef enum {
AHC_NONE = 0x0000,
AHC_CHIPID_MASK = 0x00FF,
@@ -94,10 +124,10 @@ typedef enum {
AHC_AIC7860 = 0x0005,
AHC_AIC7870 = 0x0006,
AHC_AIC7880 = 0x0007,
- AHC_AIC7890 = 0x0008,
- AHC_AIC7892 = 0x0009,
- AHC_AIC7895 = 0x000a,
- AHC_AIC7896 = 0x000b,
+ AHC_AIC7895 = 0x0008,
+ AHC_AIC7890 = 0x0009,
+ AHC_AIC7896 = 0x000a,
+ AHC_AIC7892 = 0x000b,
AHC_AIC7899 = 0x000c,
AHC_VL = 0x0100, /* Bus type VL */
AHC_EISA = 0x0200, /* Bus type EISA */
@@ -123,26 +153,42 @@ typedef enum {
AHC_DT = 0x0800, /* Double Transition transfers */
AHC_NEW_TERMCTL = 0x1000,
AHC_MULTI_FUNC = 0x2000, /* Multi-Function Twin Channel Device */
- AHC_TARG_DMABUG = 0x4000, /* WideOdd Data-In bug in TMODE */
- AHC_AIC7770_FE = AHC_TARG_DMABUG,
- AHC_AIC7850_FE = AHC_TARG_DMABUG|AHC_SPIOCAP,
+ AHC_LARGE_SCBS = 0x4000, /* 64byte SCBs */
+ AHC_AIC7770_FE = AHC_FENONE,
+ AHC_AIC7850_FE = AHC_SPIOCAP,
AHC_AIC7855_FE = AHC_AIC7850_FE,
AHC_AIC7859_FE = AHC_AIC7850_FE|AHC_ULTRA,
AHC_AIC7860_FE = AHC_AIC7859_FE,
- AHC_AIC7870_FE = AHC_TARG_DMABUG,
- AHC_AIC7880_FE = AHC_TARG_DMABUG|AHC_ULTRA,
+ AHC_AIC7870_FE = AHC_FENONE,
+ AHC_AIC7880_FE = AHC_ULTRA,
AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|AHC_QUEUE_REGS
|AHC_SG_PRELOAD|AHC_MULTI_TID|AHC_HS_MAILBOX
- |AHC_NEW_TERMCTL,
+ |AHC_NEW_TERMCTL|AHC_LARGE_SCBS,
AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_DT,
AHC_AIC7895_FE = AHC_AIC7880_FE|AHC_MORE_SRAM
- |AHC_CMD_CHAN|AHC_MULTI_FUNC,
+ |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS,
AHC_AIC7895C_FE = AHC_AIC7895_FE|AHC_MULTI_TID,
AHC_AIC7896_FE = AHC_AIC7890_FE|AHC_MULTI_FUNC,
AHC_AIC7899_FE = AHC_AIC7892_FE|AHC_MULTI_FUNC
} ahc_feature;
typedef enum {
+ AHC_BUGNONE = 0x00,
+ /*
+ * On all chips prior to the U2 product line,
+ * the WIDEODD S/G segment feature does not
+ * work during scsi->HostBus transfers.
+ */
+ AHC_TMODE_WIDEODD_BUG = 0x01,
+ /*
+ * On the aic7890/91 Rev 0 chips, the autoflush
+ * feature does not work. A manual flush of
+ * the DMA FIFO is required.
+ */
+ AHC_AUTOFLUSH_BUG = 0x02
+} ahc_bug;
+
+typedef enum {
AHC_FNONE = 0x000,
AHC_PAGESCBS = 0x001,/* Enable SCB paging */
AHC_CHANNEL_B_PRIMARY = 0x002,/*
@@ -179,8 +225,23 @@ typedef enum {
* Internal 50pin connector
* sits behind an aic3860
*/
+ AHC_SCB_BTT = 0x40000 /*
+ * The busy targets table is
+ * stored in SCB space rather
+ * than SRAM.
+ */
} ahc_flag;
+struct ahc_probe_config {
+ const char *description;
+ char channel;
+ char channel_b;
+ ahc_chip chip;
+ ahc_feature features;
+ ahc_bug bugs;
+ ahc_flag flags;
+};
+
typedef enum {
SCB_FREE = 0x0000,
SCB_OTHERTCL_TIMEOUT = 0x0002,/*
@@ -194,6 +255,7 @@ typedef enum {
SCB_DEVICE_RESET = 0x0004,
SCB_SENSE = 0x0008,
SCB_RECOVERY_SCB = 0x0040,
+ SCB_NEGOTIATE = 0x0080,
SCB_ABORT = 0x1000,
SCB_QUEUED_MSG = 0x2000,
SCB_ACTIVE = 0x4000,
@@ -204,57 +266,116 @@ typedef enum {
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
* consists of a "hardware SCB" mirroring the fields availible on the card
* and additional information the kernel stores for each transaction.
+ *
+ * To minimize space utilization, a portion of the hardware scb stores
+ * different data during different portions of a SCSI transaction.
+ * As initialized by the host driver for the initiator role, this area
+ * contains the SCSI cdb (or pointer to the cdb) to be executed. After
+ * the cdb has been presented to the target, this area serves to store
+ * residual transfer information and the SCSI status byte.
+ * For the target role, the contents of this area do not change, but
+ * still serve a different purpose than for the initiator role. See
+ * struct target_data for details.
*/
+
+struct status_pkt {
+ uint32_t residual_datacnt;
+ uint32_t residual_sg_ptr;
+ uint8_t scsi_status;
+};
+
+struct target_data {
+ uint8_t target_phases;
+ uint8_t data_phase;
+ uint8_t scsi_status;
+ uint8_t initiator_tag;
+};
+
struct hardware_scb {
-/*0*/ u_int8_t control;
-/*1*/ u_int8_t tcl; /* 4/1/3 bits */
-/*2*/ u_int8_t status;
-/*3*/ u_int8_t SG_count;
-/*4*/ u_int32_t SG_pointer;
-/*8*/ u_int8_t residual_SG_count;
-/*9*/ u_int8_t residual_data_count[3];
-/*12*/ u_int32_t data;
-/*16*/ u_int32_t datalen; /* Really only three bytes, but its
- * faster to treat it as a long on
- * a quad boundary.
+/*0*/ uint8_t control;
+/*1*/ uint8_t scsiid; /* what to load in the SCSIID register */
+/*2*/ uint8_t lun;
+/*3*/ uint8_t cdb_len;
+/*4*/ union {
+ /*
+ * 12 bytes of cdb information only
+ * used on chips with 32byte SCBs.
+ */
+ uint8_t cdb[12];
+ uint32_t cdb_ptr;
+ struct status_pkt status;
+ struct target_data tdata;
+ } shared_data;
+/*
+ * A word about residuals. The scb is presented to the sequencer with
+ * the dataptr and datacnt fields initialized to the contents of the
+ * first S/G element to transfer. The sgptr field is initialized to
+ * the bus address for the S/G element that follows the first in the
+ * in core S/G array or'ed with the SG_FULL_RESID flag. Sgptr may point
+ * to an invalid S/G entry for this transfer. If no transfer is to occur,
+ * sgptr is set to SG_LIST_NULL. The SG_FULL_RESID flag insures that
+ * the residual will be correctly noted even if no data transfers occur.
+ * Once the data phase is entered, the residual sgptr and datacnt are
+ * loaded from the sgptr and the datacnt fields. After each S/G element's
+ * dataptr and length are loaded into the hardware, the residual sgptr
+ * is advanced. After each S/G element is expired, its datacnt field
+ * is checked to see if the LAST_SEG flag is set. If so, SG_LIST_NULL
+ * is set in the residual sg ptr and the transfer is considered complete.
+ * If the sequencer determines that three is a residual in the tranfer,
+ * it will set the SG_RESID_VALID flag in sgptr and dma the scb back into
+ * host memory. To sumarize:
+ *
+ * Sequencer:
+ * o A residual has occurred if SG_FULL_RESID is set in sgptr,
+ * or residual_sgptr does not have SG_LIST_NULL set.
+ *
+ * o We are transfering the last segment if residual_datacnt has
+ * the SG_LAST_SEG flag set.
+ *
+ * Host:
+ * o A residual has occurred if a completed scb has the
+ * SG_RESID_VALID flag set.
+ *
+ * o residual_sgptr and sgptr refer to the "next" sg entry
+ * and so may point beyond the last valid sg entry for the
+ * transfer.
+ */
+/*16*/ uint32_t dataptr;
+/*20*/ uint32_t datacnt; /*
+ * The highest address byte is
+ * really the 5th. byte in the
+ * dataptr.
*/
-/*20*/ u_int32_t cmdpointer;
-/*24*/ u_int8_t cmdlen;
-/*25*/ u_int8_t tag; /* Index into our kernel SCB array.
+/*24*/ uint32_t sgptr;
+#define SG_PTR_MASK 0xFFFFFFF8
+/*28*/ uint8_t tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
*/
-/*26*/ u_int8_t next; /* Used for threading SCBs in the
+/*29*/ uint8_t scsirate; /* Value for SCSIRATE register */
+/*30*/ uint8_t scsioffset; /* Value for SCSIOFFSET register */
+/*31*/ uint8_t next; /* Used for threading SCBs in the
* "Waiting for Selection" and
* "Disconnected SCB" lists down
* in the sequencer.
*/
-/*27*/ u_int8_t scsirate; /* Value for SCSIRATE register */
-/*28*/ u_int8_t scsioffset; /* Value for SCSIOFFSET register */
-/*29*/ u_int8_t spare[3]; /*
- * Spare space available on
- * all controller types.
- */
-/*32*/ u_int8_t cmdstore[16]; /*
+/*32*/ uint8_t cdb32[32]; /*
* CDB storage for controllers
* supporting 64 byte SCBs.
*/
-/*48*/ u_int32_t cmdstore_busaddr; /*
- * Address of command store for
- * 32byte SCB adapters
- */
-/*48*/ u_int8_t spare_64[12]; /*
- * Pad to 64 bytes.
- */
};
struct scb {
struct hardware_scb *hscb;
- SLIST_ENTRY(scb) links; /* for chaining */
+ union {
+ SLIST_ENTRY(scb) sle;
+ TAILQ_ENTRY(scb) tqe;
+ } links;
union ccb *ccb; /* the ccb for this cmd */
scb_flag flags;
bus_dmamap_t dmamap;
struct ahc_dma_seg *sg_list;
bus_addr_t sg_list_phys;
+ bus_addr_t cdb32_busaddr;
u_int sg_count;/* How full ahc_dma_seg is */
};
@@ -267,12 +388,11 @@ struct scb {
* which only has limited direct access to the DMA FIFO.
*/
struct target_cmd {
- u_int8_t initiator_channel;
- u_int8_t targ_id; /* Target ID we were selected at */
- u_int8_t identify; /* Identify message */
- u_int8_t bytes[21];
- u_int8_t cmd_valid;
- u_int8_t pad[7];
+ uint8_t scsiid;
+ uint8_t identify; /* Identify message */
+ uint8_t bytes[22];
+ uint8_t cmd_valid;
+ uint8_t pad[7];
};
/*
@@ -281,10 +401,10 @@ struct target_cmd {
*/
#define AHC_TMODE_EVENT_BUFFER_SIZE 8
struct ahc_tmode_event {
- u_int8_t initiator_id;
- u_int8_t event_type; /* MSG type or EVENT_TYPE_BUS_RESET */
+ uint8_t initiator_id;
+ uint8_t event_type; /* MSG type or EVENT_TYPE_BUS_RESET */
#define EVENT_TYPE_BUS_RESET 0xFF
- u_int8_t event_arg;
+ uint8_t event_arg;
};
/*
@@ -296,8 +416,8 @@ struct tmode_lstate {
struct ccb_hdr_slist accept_tios;
struct ccb_hdr_slist immed_notifies;
struct ahc_tmode_event event_buffer[AHC_TMODE_EVENT_BUFFER_SIZE];
- u_int8_t event_r_idx;
- u_int8_t event_w_idx;
+ uint8_t event_r_idx;
+ uint8_t event_w_idx;
};
#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */
@@ -306,14 +426,16 @@ struct tmode_lstate {
#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */
struct ahc_transinfo {
- u_int8_t width;
- u_int8_t period;
- u_int8_t offset;
- u_int8_t ppr_flags;
+ uint8_t protocol_version;
+ uint8_t transport_version;
+ uint8_t width;
+ uint8_t period;
+ uint8_t offset;
+ uint8_t ppr_options;
};
struct ahc_initiator_tinfo {
- u_int8_t scsirate;
+ uint8_t scsirate;
struct ahc_transinfo current;
struct ahc_transinfo goal;
struct ahc_transinfo user;
@@ -326,15 +448,15 @@ struct ahc_initiator_tinfo {
* are the initiator).
*/
struct tmode_tstate {
- struct tmode_lstate* enabled_luns[8];
+ struct tmode_lstate* enabled_luns[64];
struct ahc_initiator_tinfo transinfo[16];
/*
* Per initiator state bitmasks.
*/
- u_int16_t ultraenb; /* Using ultra sync rate */
- u_int16_t discenable; /* Disconnection allowed */
- u_int16_t tagenable; /* Tagged Queuing allowed */
+ uint16_t ultraenb; /* Using ultra sync rate */
+ uint16_t discenable; /* Disconnection allowed */
+ uint16_t tagenable; /* Tagged Queuing allowed */
};
/*
@@ -345,7 +467,7 @@ struct seeprom_config {
/*
* SCSI ID Configuration Flags
*/
- u_int16_t device_flags[16]; /* words 0-15 */
+ uint16_t device_flags[16]; /* words 0-15 */
#define CFXFER 0x0007 /* synchronous transfer rate */
#define CFSYNCH 0x0008 /* enable synchronous transfer */
#define CFDISC 0x0010 /* enable disconnection */
@@ -355,28 +477,29 @@ struct seeprom_config {
#define CFSTART 0x0100 /* send start unit SCSI command */
#define CFINCBIOS 0x0200 /* include in BIOS scan */
#define CFRNFOUND 0x0400 /* report even if not found */
-#define CFMULTILUN 0x0800 /* Probe multiple luns in BIOS scan */
+#define CFMULTILUNDEV 0x0800 /* Probe multiple luns in BIOS scan */
#define CFWBCACHEENB 0x4000 /* Enable W-Behind Cache on disks */
#define CFWBCACHENOP 0xc000 /* Don't touch W-Behind Cache */
/*
* BIOS Control Bits
*/
- u_int16_t bios_control; /* word 16 */
+ uint16_t bios_control; /* word 16 */
#define CFSUPREM 0x0001 /* support all removeable drives */
#define CFSUPREMB 0x0002 /* support removeable boot drives */
#define CFBIOSEN 0x0004 /* BIOS enabled */
/* UNUSED 0x0008 */
#define CFSM2DRV 0x0010 /* support more than two drives */
#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
-/* UNUSED 0x0040 */
+#define CFSTPWLEVEL 0x0010 /* Termination level control */
#define CFEXTEND 0x0080 /* extended translation enabled */
+#define CFSCAMEN 0x0100 /* SCAM enable */
/* UNUSED 0xff00 */
/*
* Host Adapter Control Bits
*/
- u_int16_t adapter_control; /* word 17 */
+ uint16_t adapter_control; /* word 17 */
#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
@@ -385,16 +508,19 @@ struct seeprom_config {
#define CFWSTERM 0x0008 /* SCSI high byte termination */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */
+#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
+#define CFCLUSTERENB 0x0080 /* Cluster Enable */
#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */
-#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Termination*/
-#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */
-/* UNUSED 0xf280 */
+#define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/
+#define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */
+#define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */
+#define CFDOMAINVAL 0x4000 /* Perform Domain Validation*/
/*
* Bus Release, Host Adapter ID
*/
- u_int16_t brtime_id; /* word 18 */
+ uint16_t brtime_id; /* word 18 */
#define CFSCSIID 0x000f /* host adapter SCSI ID */
/* UNUSED 0x00f0 */
#define CFBRTIME 0xff00 /* bus release time */
@@ -402,20 +528,24 @@ struct seeprom_config {
/*
* Maximum targets
*/
- u_int16_t max_targets; /* word 19 */
+ uint16_t max_targets; /* word 19 */
#define CFMAXTARG 0x00ff /* maximum targets */
-/* UNUSED 0xff00 */
- u_int16_t res_1[11]; /* words 20-30 */
- u_int16_t checksum; /* word 31 */
+#define CFBOOTLUN 0x0f00 /* Lun to boot from */
+#define CFBOOTID 0xf000 /* Target to boot from */
+ uint16_t res_1[10]; /* words 20-29 */
+ uint16_t signature; /* Signature == 0x250 */
+#define CFSIGNATURE 0x250
+ uint16_t checksum; /* word 31 */
};
struct ahc_syncrate {
- int sxfr_u2;
- int sxfr;
+ u_int sxfr_u2;
+ u_int sxfr;
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
-#define ST_SXFR 0x010
- u_int8_t period; /* Period to send to SCSI target */
+#define ST_SXFR 0x010 /* Rate Single Transition Only */
+#define DT_SXFR 0x040 /* Rate Double Transition Only */
+ uint8_t period; /* Period to send to SCSI target */
char *rate;
};
@@ -454,14 +584,16 @@ struct scb_data {
bus_addr_t sense_busaddr;
bus_dma_tag_t sg_dmat; /* dmat for our sg segments */
SLIST_HEAD(, sg_map_node) sg_maps;
- u_int8_t numscbs;
- u_int8_t maxhscbs; /* Number of SCBs on the card */
- u_int8_t init_level; /*
+ uint8_t numscbs;
+ uint8_t maxhscbs; /* Number of SCBs on the card */
+ uint8_t init_level; /*
* How far we've initialized
* this structure.
*/
};
+TAILQ_HEAD(scb_tailq, scb);
+
struct ahc_softc {
bus_space_tag_t tag;
bus_space_handle_t bsh;
@@ -474,6 +606,23 @@ struct ahc_softc {
LIST_HEAD(, ccb_hdr) pending_ccbs;
/*
+ * Counting lock for deferring the release of additional
+ * untagged transactions from the untagged_queues. When
+ * the lock is decremented to 0, all queues in the
+ * untagged_queues array are run.
+ */
+ u_int untagged_queue_lock;
+
+ /*
+ * Per-target queue of untagged-transactions. The
+ * transaction at the head of the queue is the
+ * currently pending untagged transaction for the
+ * target. The driver only allows a single untagged
+ * transaction per target.
+ */
+ struct scb_tailq untagged_queues[16];
+
+ /*
* Target mode related state kept on a per enabled lun basis.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -498,23 +647,18 @@ struct ahc_softc {
*/
ahc_chip chip;
ahc_feature features;
+ ahc_bug bugs;
ahc_flag flags;
/* Values to store in the SEQCTL register for pause and unpause */
- u_int8_t unpause;
- u_int8_t pause;
+ uint8_t unpause;
+ uint8_t pause;
/* Command Queues */
- u_int8_t qoutfifonext;
- u_int8_t qinfifonext;
- u_int8_t *qoutfifo;
- u_int8_t *qinfifo;
-
- /*
- * 256 byte array storing the SCBID of outstanding
- * untagged SCBs indexed by TCL.
- */
- u_int8_t *untagged_scbs;
+ uint8_t qoutfifonext;
+ uint8_t qinfifonext;
+ uint8_t *qoutfifo;
+ uint8_t *qinfifo;
/*
* Hooks into the XPT.
@@ -531,11 +675,11 @@ struct ahc_softc {
char channel_b;
/* Initiator Bus ID */
- u_int8_t our_id;
- u_int8_t our_id_b;
+ uint8_t our_id;
+ uint8_t our_id_b;
/* Targets that need negotiation messages */
- u_int16_t targ_msg_req;
+ uint16_t targ_msg_req;
/*
* PCI error detection and data for running the
@@ -548,15 +692,15 @@ struct ahc_softc {
* Target incoming command FIFO.
*/
struct target_cmd *targetcmds;
- u_int8_t tqinfifonext;
+ uint8_t tqinfifonext;
/*
* Incoming and outgoing message handling.
*/
- u_int8_t send_msg_perror;
+ uint8_t send_msg_perror;
ahc_msg_type msg_type;
- u_int8_t msgout_buf[8]; /* Message we are sending */
- u_int8_t msgin_buf[8]; /* Message we are receiving */
+ uint8_t msgout_buf[8]; /* Message we are sending */
+ uint8_t msgin_buf[8]; /* Message we are receiving */
u_int msgout_len; /* Length of message to send */
u_int msgout_index; /* Current index in msgout */
u_int msgin_index; /* Current index in msgin */
@@ -579,8 +723,8 @@ struct ahc_softc {
/* Initialization level of this data structure */
u_int init_level;
- u_int16_t user_discenable;/* Disconnection allowed */
- u_int16_t user_tagenable;/* Tagged Queuing allowed */
+ uint16_t user_discenable;/* Disconnection allowed */
+ uint16_t user_tagenable;/* Tagged Queuing allowed */
};
struct full_ahc_softc {
@@ -601,30 +745,76 @@ struct full_ahc_softc {
extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
#endif
+#define ahc_inb(ahc, port) \
+ bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
+
+#define ahc_outb(ahc, port, value) \
+ bus_space_write_1((ahc)->tag, (ahc)->bsh, port, value)
+
+#define ahc_outsb(ahc, port, valp, count) \
+ bus_space_write_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
+
+#define ahc_insb(ahc, port, valp, count) \
+ bus_space_read_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
+
char *ahc_name(struct ahc_softc *ahc);
+void ahc_init_probe_config(struct ahc_probe_config *config);
struct ahc_softc*
ahc_alloc(device_t dev, struct resource *regs, int regs_type,
- int regs_id, bus_dma_tag_t parent_dmat, ahc_chip chip,
- ahc_feature features, ahc_flag flags,
- struct scb_data *scb_data);
+ int regs_id, bus_dma_tag_t parent_dmat,
+ struct ahc_probe_config *config, struct scb_data *scb_data);
int ahc_reset(struct ahc_softc *ahc);
void ahc_free(struct ahc_softc *);
int ahc_probe_scbs(struct ahc_softc *);
int ahc_init(struct ahc_softc *);
int ahc_attach(struct ahc_softc *);
void ahc_intr(void *arg);
+static __inline int sequencer_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_bug_fix(struct ahc_softc *ahc)
+{
+ /*
+ * Clear the CIOBUS stretch signal by reading a register that will
+ * set this signal and deassert it. Without this workaround, if
+ * the chip is paused, by an interrupt or manual pause, while
+ * accessing scb ram, then accesses to certain registers will hang
+ * the system (infinite pci retries).
+ */
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ (void)ahc_inb(ahc, CCSCBCTL);
+}
-#define ahc_inb(ahc, port) \
- bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
-
-#define ahc_outb(ahc, port, value) \
- bus_space_write_1((ahc)->tag, (ahc)->bsh, port, value)
+static __inline int
+sequencer_paused(struct ahc_softc *ahc)
+{
+ return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
+}
-#define ahc_outsb(ahc, port, valp, count) \
- bus_space_write_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
+static __inline void
+pause_sequencer(struct ahc_softc *ahc)
+{
+ ahc_outb(ahc, HCNTRL, ahc->pause);
-#define ahc_insb(ahc, port, valp, count) \
- bus_space_read_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
+ /*
+ * Since the sequencer can disable pausing in a critical section, we
+ * must loop until it actually stops.
+ */
+ while (sequencer_paused(ahc) == 0)
+ ;
+
+ ahc_pause_bug_fix(ahc);
+}
+
+static __inline void
+unpause_sequencer(struct ahc_softc *ahc)
+{
+ if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
+ ahc_outb(ahc, HCNTRL, ahc->unpause);
+}
#endif /* _AIC7XXX_H_ */
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
index 78c95a8..d76f44c 100644
--- a/sys/dev/aic7xxx/aic7xxx.reg
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -14,7 +14,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -172,6 +172,8 @@ register SCSIID {
address 0x005
access_mode RW
mask TID 0xf0 /* Target ID mask */
+ mask TWIN_TID 0x70
+ bit TWIN_CHNLB 0x80
mask OID 0x0f /* Our ID mask */
/*
* SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
@@ -704,7 +706,6 @@ register HS_MAILBOX {
address 0x086
mask HOST_MAILBOX 0xF0
mask SEQ_MAILBOX 0x0F
- mask HOST_REQ_INT 0x10
mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */
}
@@ -746,7 +747,7 @@ register HCNT {
/*
* SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
+ * Gate one of the SCBs into the SCBARRAY window.
*/
register SCBPTR {
address 0x090
@@ -768,10 +769,10 @@ register INTSTAT {
mask SEND_REJECT 0x10|SEQINT /* sending a message reject */
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
- mask UPDATE_TMSG_REQ 0x60|SEQINT /* Update TMSG_REQ values */
+ mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */
mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
- mask TRACE_POINT 0x90|SEQINT
+ mask TRACEPOINT2 0x90|SEQINT
mask HOST_MSG_LOOP 0xa0|SEQINT /*
* The bus is ready for the
* host to perform another
@@ -787,11 +788,6 @@ register INTSTAT {
* noticed a parity error.
*/
mask TRACEPOINT 0xd0|SEQINT
- mask MSGIN_PHASEMIS 0xe0|SEQINT /*
- * Target changed phase on us
- * when we were expecting
- * another msgin byte.
- */
mask DATA_OVERRUN 0xf0|SEQINT /*
* Target attempted to write
* beyond the bounds of its
@@ -962,33 +958,41 @@ scb {
address 0x0a0
SCB_CONTROL {
size 1
- bit TARGET_SCB 0x80
- bit DISCENB 0x40
- bit TAG_ENB 0x20
- bit MK_MESSAGE 0x10
- bit ULTRAENB 0x08
- bit DISCONNECTED 0x04
- mask SCB_TAG_TYPE 0x03
+ bit TARGET_SCB 0x80
+ bit DISCENB 0x40
+ bit TAG_ENB 0x20
+ bit MK_MESSAGE 0x10
+ bit ULTRAENB 0x08
+ bit DISCONNECTED 0x04
+ mask SCB_TAG_TYPE 0x03
}
- SCB_TCL {
+ SCB_SCSIID {
size 1
- bit SELBUSB 0x08
- mask TID 0xf0
- mask LID 0x07
+ bit TWIN_CHNLB 0x80
+ mask TWIN_TID 0x70
+ mask TID 0xf0
+ mask OID 0x0f
}
- SCB_TARGET_STATUS {
+ SCB_LUN {
+ mask LID 0xff
size 1
}
- SCB_SGCOUNT {
+ SCB_CDB_LEN {
size 1
}
- SCB_SGPTR {
+ SCB_CDB_PTR {
+ size 4
+ alias SCB_RESIDUAL_DATACNT
+ alias SCB_CDB_STORE
+ alias SCB_TARGET_INFO
+ }
+ SCB_RESIDUAL_SGPTR {
size 4
}
- SCB_RESID_SGCNT {
+ SCB_SCSI_STATUS {
size 1
}
- SCB_RESID_DCNT {
+ SCB_CDB_STORE_PAD {
size 3
}
SCB_DATAPTR {
@@ -996,48 +1000,41 @@ scb {
}
SCB_DATACNT {
/*
- * Really only 3 bytes, but padded to make
- * the kernel's job easier.
+ * The last byte is really the high address bits for
+ * the data address.
*/
size 4
+ bit SG_LAST_SEG 0x80 /* In the fourth byte */
+ mask SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */
}
- SCB_CMDPTR {
- alias SCB_TARGET_PHASES
- bit TARGET_DATA_IN 0x1 /* In the second byte */
+ SCB_SGPTR {
size 4
- }
- SCB_CMDLEN {
- alias SCB_INITIATOR_TAG
- size 1
+ bit SG_RESID_VALID 0x04 /* In the first byte */
+ bit SG_FULL_RESID 0x02 /* In the first byte */
+ bit SG_LIST_NULL 0x01 /* In the first byte */
}
SCB_TAG {
size 1
}
- SCB_NEXT {
- size 1
- }
SCB_SCSIRATE {
size 1
}
SCB_SCSIOFFSET {
size 1
}
- SCB_SPARE {
- size 3
+ SCB_NEXT {
+ size 1
}
- SCB_CMDSTORE {
+ SCB_64_BTT {
size 16
}
- SCB_CMDSTORE_BUSADDR {
- size 4
- }
- SCB_64BYTE_SPARE {
- size 12
+ SCB_64_SPARE {
+ size 16
}
}
-const SCB_32BYTE_SIZE 28
-const SCB_64BYTE_SIZE 48
+const SCB_32BYTE_SIZE 30 /* Cards supporting 32byte scbs */
+const SCB_64BYTE_SIZE 32 /* Cards supporting 64byte scbs */
const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
@@ -1083,7 +1080,7 @@ register CCSGCTL {
address 0x0EB
bit CCSGDONE 0x80
bit CCSGEN 0x08
- bit FLAG 0x02
+ bit SG_FETCH_NEEDED 0x02 /* Bit used for software state */
bit CCSGRESET 0x01
}
@@ -1164,14 +1161,23 @@ register DFF_THRSH {
mask WR_DFTHRSH_MAX 0x70
}
-register SG_CACHEPTR {
- access_mode RW
+register SG_CACHE_PRE {
+ access_mode WO
address 0x0fc
- mask SG_USER_DATA 0xfc
+ mask SG_ADDR_MASK 0xf8
+ bit ODD_SEG 0x04
bit LAST_SEG 0x02
bit LAST_SEG_DONE 0x01
}
+register SG_CACHE_SHADOW {
+ access_mode RO
+ address 0x0fc
+ mask SG_ADDR_MASK 0xf8
+ bit ODD_SEG 0x04
+ bit LAST_SEG 0x02
+ bit LAST_SEG_DONE 0x01
+}
/* ---------------------- Scratch RAM Offsets ------------------------- */
/* These offsets are either to values that are initialized by the board's
* BIOS or are specified by the sequencer code.
@@ -1193,8 +1199,11 @@ scratch_ram {
/*
* 1 byte per target starting at this address for configuration values
*/
- TARG_SCSIRATE {
- alias CMDSIZE_TABLE
+ CMDSIZE_TABLE {
+ alias TARG_SCSIRATE
+ size 8
+ }
+ BUSY_TARGETS {
size 16
}
/*
@@ -1234,6 +1243,7 @@ scratch_ram {
size 1
bit IDENTIFY_SEEN 0x80
bit SCBPTR_VALID 0x40
+ bit TARGET_CMD_IS_TAGGED 0x40
bit DPHASE 0x20
/* Target flags */
bit TARG_CMD_PENDING 0x10
@@ -1247,17 +1257,12 @@ scratch_ram {
* target/channel/lun of a
* reconnecting target
*/
- SAVED_TCL {
+ SAVED_SCSIID {
size 1
}
- /* Working value of the number of SG segments left */
- SG_COUNT {
+ SAVED_LUN {
size 1
}
- /* Working value of SG pointer */
- SG_NEXT {
- size 4
- }
/*
* The last bus phase as seen by the sequencer.
*/
@@ -1304,17 +1309,11 @@ scratch_ram {
size 4
}
/*
- * Address of the 256 byte array storing the SCBID of outstanding
- * untagged SCBs indexed by TCL.
+ * Base address of our shared data with the kernel driver in host
+ * memory. This includes the qinfifo, qoutfifo, and target mode
+ * incoming command queue.
*/
- SCBID_ADDR {
- size 4
- }
- /*
- * Address of the array of command descriptors used to store
- * information about incoming selections.
- */
- TMODE_CMDADDR {
+ SHARED_DATA_ADDR {
size 4
}
KERNEL_QINPOS {
@@ -1361,14 +1360,6 @@ scratch_ram {
}
/*
- * Number of times we have filled the CCSGRAM with prefetched
- * SG elements.
- */
- PREFETCH_CNT {
- size 1
- }
-
- /*
* Interrupt kernel for a message to this target on
* the next transaction. This is usually used for
* negotiation requests.
@@ -1441,17 +1432,13 @@ scratch_ram {
}
}
+const TID_SHIFT 4
const SCB_LIST_NULL 0xff
const TARGET_CMD_CMPLT 0xfe
const CCSGADDR_MAX 0x80
const CCSGRAM_MAXSEGS 16
-/* Offsets into the SCBID array where different data is stored */
-const QOUTFIFO_OFFSET 0
-const QINFIFO_OFFSET 1
-const UNTAGGEDSCB_OFFSET 2
-
/* WDTR Message values */
const BUS_8_BIT 0x00
const BUS_16_BIT 0x01
@@ -1466,18 +1453,17 @@ const HOST_MSG 0xff
/* Target mode command processing constants */
const CMD_GROUP_CODE_SHIFT 0x05
-const TCL_TARGET_SHIFT 4
-
const STATUS_BUSY 0x08
-const STATUS_QUEUE_FULL 0x28
+const STATUS_QUEUE_FULL 0x28
+const SCB_TARGET_PHASES 0
+const SCB_TARGET_DATA_DIR 1
+const SCB_TARGET_STATUS 2
+const SCB_INITIATOR_TAG 3
+const TARGET_DATA_IN 1
/*
* Downloaded (kernel inserted) constants
*/
-
-/*
- * Number of command descriptors in the command descriptor array.
- * No longer used, but left here as an example for how downloaded
- * constantants can be defined.
-const TMODE_NUMCMDS download
- */
+/* Offsets into the SCBID array where different data is stored */
+const QOUTFIFO_OFFSET download
+const QINFIFO_OFFSET download
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index 187b22e..d2df34d 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -14,7 +14,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -71,9 +71,6 @@ poll_for_work:
mov A, QINPOS;
}
poll_for_work_loop:
- if ((ahc->features & AHC_QUEUE_REGS) == 0) {
- and SEQCTL, ~PAUSEDIS;
- }
test SSTAT0, SELDO|SELDI jnz selection;
test SCSISEQ, ENSELO jnz poll_for_work_loop;
if ((ahc->features & AHC_TWIN) != 0) {
@@ -85,8 +82,7 @@ poll_for_work_loop:
*/
xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
test SSTAT0, SELDO|SELDI jnz selection;
- test SCSISEQ, ENSELO jnz poll_for_work;
- xor SBLKCTL,SELBUSB; /* Toggle back */
+ test SCSISEQ, ENSELO jnz poll_for_work_loop;
}
cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
test_queue:
@@ -96,18 +92,15 @@ test_queue:
mov NONE, SNSCB_QOFF;
inc QINPOS;
} else {
- or SEQCTL, PAUSEDIS;
cmp KERNEL_QINPOS, A je poll_for_work_loop;
inc QINPOS;
- and SEQCTL, ~PAUSEDIS;
}
-/*
- * We have at least one queued SCB now and we don't have any
- * SCBs in the list of SCBs awaiting selection. If we have
- * any SCBs available for use, pull the tag from the QINFIFO
- * and get to work on it.
- */
+ /*
+ * We have at least one queued SCB now and we don't have any
+ * SCBs in the list of SCBs awaiting selection. Pull the tag
+ * from the QINFIFO and get to work on it.
+ */
if ((ahc->flags & AHC_PAGESCBS) != 0) {
mov ALLZEROS call get_free_or_disc_scb;
}
@@ -121,27 +114,12 @@ dequeue_scb:
mov SCBPTR, RETURN_2;
}
dma_queued_scb:
-/*
- * DMA the SCB from host ram into the current SCB location.
- */
+ /*
+ * DMA the SCB from host ram into the current SCB location.
+ */
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
mov RETURN_2 call dma_scb;
-/*
- * Preset the residual fields in case we never go through a data phase.
- * This isn't done by the host so we can avoid a DMA to clear these
- * fields for the normal case of I/O that completes without underrun
- * or overrun conditions.
- */
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov SCB_RESID_DCNT, SCB_DATACNT, 3;
- } else {
- mov SCB_RESID_DCNT[0],SCB_DATACNT[0];
- mov SCB_RESID_DCNT[1],SCB_DATACNT[1];
- mov SCB_RESID_DCNT[2],SCB_DATACNT[2];
- }
- mov SCB_RESID_SGCNT, SCB_SGCOUNT;
-
start_scb:
/*
* Place us on the waiting list in case our selection
@@ -151,7 +129,7 @@ start_scb:
mov WAITING_SCBH, SCBPTR;
start_waiting:
/*
- * Pull the first entry off of the waiting SCB list.
+ * Start the first entry on the waiting SCB list.
*/
mov SCBPTR, WAITING_SCBH;
call start_selection;
@@ -160,33 +138,26 @@ start_waiting:
start_selection:
if ((ahc->features & AHC_TWIN) != 0) {
and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
- and A,SELBUSB,SCB_TCL; /* Get new channel bit */
- or SINDEX,A;
+ test SCB_SCSIID, TWIN_CHNLB jz . + 2;
+ or SINDEX, SELBUSB;
mov SBLKCTL,SINDEX; /* select channel */
}
initialize_scsiid:
- mov SINDEX, SCSISEQ_TEMPLATE;
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ mov SCSIID_ULTRA2, SCB_SCSIID;
+ } else if ((ahc->features & AHC_TWIN) != 0) {
+ and SCSIID, TWIN_TID|OID, SCB_SCSIID;
+ } else {
+ mov SCSIID, SCB_SCSIID;
+ }
if ((ahc->flags & AHC_TARGETMODE) != 0) {
- test SCB_CONTROL, TARGET_SCB jz . + 4;
- if ((ahc->features & AHC_ULTRA2) != 0) {
- mov SCSIID_ULTRA2, SCB_CMDPTR[2];
- } else {
- mov SCSIID, SCB_CMDPTR[2];
- }
+ mov SINDEX, SCSISEQ_TEMPLATE;
+ test SCB_CONTROL, TARGET_SCB jz . + 2;
or SINDEX, TEMODE;
- jmp initialize_scsiid_fini;
- }
- if ((ahc->features & AHC_ULTRA2) != 0) {
- and A, TID, SCB_TCL; /* Get target ID */
- and SCSIID_ULTRA2, OID; /* Clear old target */
- or SCSIID_ULTRA2, A;
+ mov SCSISEQ, SINDEX ret;
} else {
- and A, TID, SCB_TCL; /* Get target ID */
- and SCSIID, OID; /* Clear old target */
- or SCSIID, A;
+ mov SCSISEQ, SCSISEQ_TEMPLATE ret;
}
-initialize_scsiid_fini:
- mov SCSISEQ, SINDEX ret;
/*
* Initialize transfer settings and clear the SCSI channel.
@@ -201,9 +172,9 @@ set_transfer_settings:
test SCB_CONTROL, ULTRAENB jz . + 2;
or SXFRCTL0, FAST20;
}
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
+ /*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ */
if ((ahc->features & AHC_ULTRA2) != 0) {
bmov SCSIRATE, SCB_SCSIRATE, 2 ret;
} else {
@@ -211,6 +182,13 @@ set_transfer_settings:
}
selection:
+ /*
+ * We aren't expecting a bus free, so interrupt
+ * the kernel driver if it happens.
+ */
+ mvi CLRSINT1,CLRBUSFREE;
+ or SIMODE1, ENBUSFREE;
+
test SSTAT0,SELDO jnz select_out;
mvi CLRSINT0, CLRSELDI;
select_in:
@@ -225,7 +203,6 @@ select_in:
* from the target.
*/
mvi SCSISIGO, P_MESGOUT|BSYO;
- mvi CLRSINT1, CLRBUSFREE;
/*
* Setup the DMA for sending the identify and
@@ -236,47 +213,40 @@ select_in:
mov A, TQINPOS;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi DINDEX, CCHADDR;
- mvi TMODE_CMDADDR call set_32byte_addr;
+ mvi SHARED_DATA_ADDR call set_32byte_addr;
mvi CCSCBCTL, CCSCBRESET;
} else {
mvi DINDEX, HADDR;
- mvi TMODE_CMDADDR call set_32byte_addr;
+ mvi SHARED_DATA_ADDR call set_32byte_addr;
mvi DFCNTRL, FIFORESET;
}
/* Initiator that selected us */
- and SAVED_TCL, SELID_MASK, SELID;
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- mov CCSCBRAM, SAVED_TCL;
+ and SAVED_SCSIID, SELID_MASK, SELID;
+ /* The Target ID we were selected at */
+ if ((ahc->features & AHC_MULTI_TID) != 0) {
+ and A, OID, TARGIDIN;
+ } else if ((ahc->features & AHC_ULTRA2) != 0) {
+ and A, OID, SCSIID_ULTRA2;
} else {
- mov DFDAT, SAVED_TCL;
+ and A, OID, SCSIID;
+ }
+ or SAVED_SCSIID, A;
+ if ((ahc->features & AHC_TWIN) != 0) {
+ test SBLKCTL, SELBUSB jz . + 2;
+ or SAVED_SCSIID, TWIN_CHNLB;
}
-
- /* The Target ID we were selected at */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
- if ((ahc->features & AHC_MULTI_TID) != 0) {
- and CCSCBRAM, OID, TARGIDIN;
- } else if ((ahc->features & AHC_ULTRA2) != 0) {
- and CCSCBRAM, OID, SCSIID_ULTRA2;
- } else {
- and CCSCBRAM, OID, SCSIID;
- }
+ mov CCSCBRAM, SAVED_SCSIID;
} else {
- if ((ahc->features & AHC_MULTI_TID) != 0) {
- and DFDAT, OID, TARGIDIN;
- } else if ((ahc->features & AHC_ULTRA2) != 0) {
- and DFDAT, OID, SCSIID_ULTRA2;
- } else {
- and DFDAT, OID, SCSIID;
- }
+ mov DFDAT, SAVED_SCSIID;
}
- /* No tag yet */
- mvi INITIATOR_TAG, SCB_LIST_NULL;
-
/*
* If ATN isn't asserted, the target isn't interested
* in talking to us. Go directly to bus free.
+ * XXX SCSI-1 may require us to assume lun 0 if
+ * ATN is false.
*/
test SCSISIGI, ATNI jz target_busfree;
@@ -291,7 +261,6 @@ select_in:
* Our first message must be one of IDENTIFY, ABORT, or
* BUS_DEVICE_RESET.
*/
- /* XXX May need to be more lax here for older initiators... */
test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
/* Store for host */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -341,6 +310,10 @@ select_in:
mov DFDAT, DINDEX;
}
mov INITIATOR_TAG, DINDEX;
+ or SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
+ test SCSISIGI, ATNI jz . + 2;
+ /* Initiator still wants to give us messages */
+ call target_inb;
jmp ident_messages_done;
/*
@@ -363,7 +336,7 @@ ident_messages_done:
}
cmp TQINPOS, A jne tqinfifo_has_space;
mvi P_STATUS|BSYO call change_phase;
- cmp INITIATOR_TAG, SCB_LIST_NULL je . + 3;
+ test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jnz . + 3;
mvi STATUS_QUEUE_FULL call target_outb;
jmp target_busfree_wait;
mvi STATUS_BUSY call target_outb;
@@ -376,7 +349,7 @@ tqinfifo_has_space:
mvi DFDAT, SCB_LIST_NULL;
}
or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
- test SCSISIGI, ATNI jnz target_mesgout_pending_msg;
+ test SCSISIGI, ATNI jnz target_mesgout_pending;
jmp target_ITloop;
/*
@@ -404,19 +377,18 @@ if ((ahc->flags & AHC_INITIATORMODE) != 0) {
*/
initiator_reselect:
/* XXX test for and handle ONE BIT condition */
- and SAVED_TCL, SELID_MASK, SELID;
+ and SAVED_SCSIID, SELID_MASK, SELID;
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ and A, OID, SCSIID_ULTRA2;
+ } else {
+ and A, OID, SCSIID;
+ }
+ or SAVED_SCSIID, A;
if ((ahc->features & AHC_TWIN) != 0) {
test SBLKCTL, SELBUSB jz . + 2;
- or SAVED_TCL, SELBUSB;
+ or SAVED_SCSIID, TWIN_CHNLB;
}
or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
- mvi CLRSINT1,CLRBUSFREE;
- or SIMODE1, ENBUSFREE; /*
- * We aren't expecting a
- * bus free, so interrupt
- * the kernel driver if it
- * happens.
- */
jmp ITloop;
}
@@ -432,7 +404,9 @@ select_out:
mvi CLRSINT0, CLRSELDO;
mov SCBPTR, WAITING_SCBH;
mov WAITING_SCBH,SCB_NEXT;
- mov SAVED_TCL, SCB_TCL;
+ mov SAVED_SCSIID, SCB_SCSIID;
+ mov SAVED_LUN, SCB_LUN;
+ mvi SPIOEN call initialize_channel;
if ((ahc->flags & AHC_TARGETMODE) != 0) {
test SSTAT0, TARGET jz initiator_select;
@@ -442,13 +416,11 @@ select_out:
* sending our identify messages.
*/
mvi P_MESGIN|BSYO call change_phase;
- mvi CLRSINT1,CLRBUSFREE;
/*
* Start out with a simple identify message.
*/
- and A, LID, SCB_TCL;
- or A, MSG_IDENTIFYFLAG call target_outb;
+ or SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
/*
* If we are the result of a tagged command, send
@@ -456,16 +428,14 @@ select_out:
*/
test SCB_CONTROL, TAG_ENB jz . + 3;
mvi MSG_SIMPLE_Q_TAG call target_outb;
- mov SCB_INITIATOR_TAG call target_outb;
- mov INITIATOR_TAG, SCB_INITIATOR_TAG;
+ mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb;
target_synccmd:
/*
* Now determine what phases the host wants us
* to go through.
*/
- mov SEQ_FLAGS, SCB_TARGET_PHASES;
+ mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES];
-
target_ITloop:
/*
* Start honoring ATN signals now that
@@ -493,9 +463,10 @@ target_ITloop:
target_mesgout:
mvi SCSISIGO, P_MESGOUT|BSYO;
+target_mesgout_continue:
call target_inb;
+target_mesgout_pending:
/* Local Processing goes here... */
-target_mesgout_pending_msg:
jmp host_target_message_loop;
target_disconnect:
@@ -508,6 +479,7 @@ target_busfree_wait:
/* Wait for preceeding I/O session to complete. */
test SCSISIGI, ACKI jnz .;
target_busfree:
+ and SIMODE1, ~ENBUSFREE;
clr SCSISIGO;
mvi LASTPHASE, P_BUSFREE;
call complete_target_cmd;
@@ -556,22 +528,21 @@ command_phase_done:
target_dphase:
/*
- * Data direction flags are from the
- * perspective of the initiator.
+ * Data phases on the bus are from the
+ * perspective of the initiator. The dma
+ * code looks at LASTPHASE to determine the
+ * data direction of the DMA. Toggle it for
+ * target transfers.
*/
- test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4;
- mvi LASTPHASE, P_DATAOUT;
- mvi P_DATAIN|BSYO call change_phase;
- jmp . + 3;
- mvi LASTPHASE, P_DATAIN;
- mvi P_DATAOUT|BSYO call change_phase;
- mov ALLZEROS call initialize_channel;
+ xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR];
+ or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO
+ call change_phase;
jmp p_data;
target_sphase:
mvi P_STATUS|BSYO call change_phase;
mvi LASTPHASE, P_STATUS;
- mov SCB_TARGET_STATUS call target_outb;
+ mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb;
/* XXX Watch for ATN or parity errors??? */
mvi SCSISIGO, P_MESGIN|BSYO;
/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
@@ -594,9 +565,7 @@ complete_target_cmd:
or DFCNTRL, FIFORESET;
mvi DFWADDR, 3; /* Third 64bit word or byte 24 */
mov DFDAT, ALLONES;
- mvi HCNT[0], 28;
- clr HCNT[1];
- clr HCNT[2];
+ mvi 28 call set_hcnt;
or DFCNTRL, HDMAEN|FIFOFLUSH;
call dma_finish;
}
@@ -606,15 +575,6 @@ complete_target_cmd:
if ((ahc->flags & AHC_INITIATORMODE) != 0) {
initiator_select:
- mvi SPIOEN call initialize_channel;
-
- /*
- * We aren't expecting a bus free, so interrupt
- * the kernel driver if it happens.
- */
- mvi CLRSINT1,CLRBUSFREE;
- or SIMODE1, ENBUSFREE;
-
/*
* As soon as we get a successful selection, the target
* should go into the message out phase since we have ATN
@@ -628,6 +588,7 @@ initiator_select:
* target to assert REQ before checking MSG, C/D and I/O for
* the bus phase.
*/
+mesgin_phasemis:
ITloop:
call phase_lock;
@@ -658,6 +619,7 @@ clear_target_state:
* clear DFCNTRL too.
*/
clr DFCNTRL;
+ mvi SXFRCTL0, CLRSTCNT|CLRCHN;
/*
* We don't know the target we will connect to,
@@ -668,12 +630,83 @@ clear_target_state:
bmov SCSIRATE, ALLZEROS, 2;
} else {
clr SCSIRATE;
- and SXFRCTL0, ~(FAST20);
+ if ((ahc->features & AHC_ULTRA) != 0) {
+ and SXFRCTL0, ~(FAST20);
+ }
}
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
clr SEQ_FLAGS ret;
+sg_advance:
+ clr A; /* add sizeof(struct scatter) */
+ add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
+ adc SCB_RESIDUAL_SGPTR[1],A;
+ adc SCB_RESIDUAL_SGPTR[2],A;
+ adc SCB_RESIDUAL_SGPTR[3],A ret;
+
+idle_loop:
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ /* Did we just finish fetching segs? */
+ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
+
+ /* Are we actively fetching segments? */
+ test CCSGCTL, CCSGEN jnz return;
+
+ /*
+ * Do we need any more segments?
+ */
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
+
+ /*
+ * Do we have any prefetch left???
+ */
+ cmp CCSGADDR, CCSGADDR_MAX 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;
+
+ /*
+ * The kernel allocates S/G space so that it is 128 byte
+ * aligned and ends on a 128 byte boundary. We fetch
+ * up to the next 128 byte boundary so we don't attempt
+ * to read a non-existent page.
+ */
+ mvi CCHCNT, CCSGADDR_MAX;
+ and CCHADDR[0], ~(CCSGADDR_MAX - 1), SCB_RESIDUAL_SGPTR;
+ bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
+ mvi CCSGCTL, CCSGEN|CCSGRESET ret;
+idle_sgfetch_complete:
+ mvi CCSGCTL, CCSGRESET;
+ and CCSGADDR, (CCSGADDR_MAX - 1), 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 we re-enter the data phase after going through another phase, the
* STCNT may have been cleared, so restore it from the residual field.
@@ -686,14 +719,14 @@ data_phase_reinit:
* the shaddow address.
*/
bmov HADDR, SHADDR, 4;
- bmov HCNT, SCB_RESID_DCNT, 3;
+ bmov HCNT, SCB_RESIDUAL_DATACNT, 3;
} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov STCNT, SCB_RESID_DCNT, 3;
+ bmov STCNT, SCB_RESIDUAL_DATACNT, 3;
} else {
mvi DINDEX, STCNT;
- mvi SCB_RESID_DCNT call bcopy_3;
+ mvi SCB_RESIDUAL_DATACNT call bcopy_3;
}
- and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0];
+ and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
jmp data_phase_loop;
p_data:
@@ -709,6 +742,7 @@ p_data:
* phase is okay - seen identify, etc.
*/
if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ /* We don't have any valid S/G elements */
mvi CCSGADDR, CCSGADDR_MAX;
}
test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
@@ -718,16 +752,21 @@ p_data:
/*
* Initialize the DMA address and counter from the SCB.
- * Also set SG_COUNT and SG_NEXT in memory since we cannot
- * modify the values in the SCB itself until we see a
- * save data pointers message.
+ * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
+ * flag in the highest byte of the data count. We cannot
+ * modify the saved values in the SCB until we see a save
+ * data pointers message.
*/
if ((ahc->features & AHC_CMD_CHAN) != 0) {
bmov HADDR, SCB_DATAPTR, 7;
+ bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
} else {
mvi DINDEX, HADDR;
mvi SCB_DATAPTR call bcopy_7;
+ mvi DINDEX, SCB_RESIDUAL_DATACNT + 3;
+ mvi SCB_DATACNT + 3 call bcopy_5;
}
+ and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
if ((ahc->features & AHC_ULTRA2) == 0) {
@@ -738,175 +777,273 @@ p_data:
}
}
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov SG_COUNT, SCB_SGCOUNT, 5;
- } else {
- mvi DINDEX, SG_COUNT;
- mvi SCB_SGCOUNT call bcopy_5;
- }
-
data_phase_loop:
-/* Guard against overruns */
- test SG_COUNT, 0xff jnz data_phase_inbounds;
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
+ /* Guard against overruns */
+ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
+
+ /*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
or SXFRCTL1,BITBUCKET;
and DMAPARAMS, ~(HDMAEN|SDMAEN);
+ /* Keep our idle loop from mucking with SG segments */
+ or SCB_RESIDUAL_DATACNT[0], SG_LAST_SEG;
if ((ahc->features & AHC_ULTRA2) != 0) {
bmov HCNT, ALLONES, 3;
} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
bmov STCNT, ALLONES, 3;
} else {
+ /* XXX Use bcopy? */
mvi STCNT[0], 0xFF;
mvi STCNT[1], 0xFF;
mvi STCNT[2], 0xFF;
}
data_phase_inbounds:
-/* If we are the last SG block, tell the hardware. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd;
if ((ahc->features & AHC_ULTRA2) != 0) {
- or SG_CACHEPTR, LAST_SEG;
+ mov SINDEX, SCB_RESIDUAL_SGPTR[0];
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+ or SINDEX, LAST_SEG;
+ test DATA_COUNT_ODD, 0x1 jz . + 2;
+ or SINDEX, ODD_SEG;
+ mov SG_CACHE_PRE, SINDEX;
+ mov DFCNTRL, DMAPARAMS;
+ultra2_dma_loop:
+ call idle_loop;
+ /*
+ * The transfer is complete if either the last segment
+ * completes or the target changes phase.
+ */
+ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
+ test SSTAT1,PHASEMIS jz ultra2_dma_loop;
+
+ultra2_dmafinish:
+ test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
+ and DFCNTRL, ~SCSIEN;
+ test DFCNTRL, SCSIEN jnz .;
+ultra2_dmafifoflush:
+ if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
+ /*
+ * On Rev A of the aic7890, the autoflush
+ * features doesn't function correctly.
+ * Perform an explicit manual flush. During
+ * a manual flush, the FIFOEMP bit becomes
+ * true every time the PCI FIFO empties
+ * regardless of the state of the SCSI FIFO.
+ * It can take up to 4 clock cycles for the
+ * SCSI FIFO to get data into the PCI FIFO
+ * and for FIFOEMP to de-assert. Here we
+ * guard against this condition by making
+ * sure the FIFOEMP bit stays on for 5 full
+ * clock cycles.
+ */
+ or DFCNTRL, FIFOFLUSH;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ }
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ultra2_dmafifoempty:
+ /* Don't clobber an inprogress host data transfer */
+ test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty;
+ultra2_dmahalt:
+ and DFCNTRL, ~(SCSIEN|HDMAEN);
+ test DFCNTRL, HDMAEN jnz .;
+
+ test SXFRCTL1,BITBUCKET jnz data_phase_finish;
+ /*
+ * Fixup the residual next S/G pointer. The S/G preload
+ * feature of the chip allows us to load two elements
+ * in addition to the currently active element. We
+ * store the bottom byte of the next S/G pointer in
+ * the SG_CACEPTR register so we can restore the
+ * correct value when the DMA completes. If the next
+ * sg ptr value has advanced to the point where higher
+ * bytes in the address have been affected, fix them
+ * too.
+ */
+ test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
+ test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
+ add SCB_RESIDUAL_SGPTR[1], -1;
+ adc SCB_RESIDUAL_SGPTR[2], -1;
+ adc SCB_RESIDUAL_SGPTR[3], -1;
+sgptr_fixup_done:
+ and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
+ clr DATA_COUNT_ODD;
+ test SG_CACHE_SHADOW, ODD_SEG jz . + 2;
+ or DATA_COUNT_ODD, 0x1;
+ clr SCB_RESIDUAL_DATACNT[3];
+ test SG_CACHE_SHADOW, LAST_SEG jz data_phase_finish;
+ or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
+ /* Record if we've consumed all S/G entries */
+ test SG_CACHE_SHADOW, LAST_SEG_DONE jz . + 2;
+ or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
} else {
+ /* If we are the last SG block, tell the hardware. */
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
if ((ahc->flags & AHC_TARGETMODE) != 0) {
test SSTAT0, TARGET jz . + 2;
- test DMAPARAMS, DIRECTION jz data_phase_wideodd;
+ test DMAPARAMS, DIRECTION jz dma_mid_sg;
}
and DMAPARAMS, ~WIDEODD;
- }
-data_phase_wideodd:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- mov SINDEX, ALLONES;
+dma_mid_sg:
+ /* Start DMA data transfer. */
mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;/* Wait for preload to complete */
-data_phase_dma_loop:
- test SSTAT0, SDONE jnz data_phase_dma_done;
- test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
- } else {
- mov DMAPARAMS call dma;
- }
-
-data_phase_dma_done:
-/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
-
-/* See if we completed this segment */
- test STCNT[0], 0xff jnz data_phase_finish;
- test STCNT[1], 0xff jnz data_phase_finish;
- test STCNT[2], 0xff jnz data_phase_finish;
-
-/*
- * Advance the scatter-gather pointers if needed
- */
-sg_advance:
- dec SG_COUNT; /* one less segment to go */
-
- test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
+dma_loop:
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ call idle_loop;
+ }
+ test SSTAT0,DMADONE jnz dma_dmadone;
+ test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */
+dma_phasemis:
/*
- * Do we have any prefetch left???
+ * We will be "done" DMAing when the transfer count goes to
+ * zero, or the target changes the phase (in light of this,
+ * it makes sense that the DMA circuitry doesn't ACK when
+ * PHASEMIS is active). If we are doing a SCSI->Host transfer,
+ * the data FIFO should be flushed auto-magically on STCNT=0
+ * or a phase change, so just wait for FIFO empty status.
*/
- cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+dma_checkfifo:
+ test DFCNTRL,DIRECTION jnz dma_fifoempty;
+dma_fifoflush:
+ test DFSTATUS,FIFOEMP jz dma_fifoflush;
+dma_fifoempty:
+ /* Don't clobber an inprogress host data transfer */
+ test DFSTATUS, MREQPEND jnz dma_fifoempty;
/*
- * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+ * Now shut off the DMA and make sure that the DMA
+ * hardware has actually stopped. Touching the DMA
+ * counters, etc. while a DMA is active will result
+ * in an ILLSADDR exception.
*/
- add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
- mvi A, CCSGADDR_MAX;
- jc . + 2;
- shl A, 3, SG_COUNT;
- mov CCHCNT, A;
- bmov CCHADDR, SG_NEXT, 4;
- mvi CCSGCTL, CCSGEN|CCSGRESET;
- test CCSGCTL, CCSGDONE jz .;
- and CCSGCTL, ~CCSGEN;
- test CCSGCTL, CCSGEN jnz .;
- mvi CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
- bmov HADDR, CCSGRAM, 8;
- } else {
- mvi DINDEX, HADDR;
- mvi SG_NEXT call bcopy_4;
-
- mvi HCNT[0],SG_SIZEOF;
- clr HCNT[1];
- clr HCNT[2];
-
- or DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
-
- call dma_finish;
-
+dma_dmadone:
+ and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
/*
- * Copy data from FIFO into SCB data pointer and data count.
- * This assumes that the SG segments are of the form:
- * struct ahc_dma_seg {
- * u_int32_t addr; four bytes, little-endian order
- * u_int32_t len; four bytes, little endian order
- * };
+ * Some revisions of the aic7880 have a problem where, if the
+ * data fifo is full, but the PCI input latch is not empty,
+ * HDMAEN cannot be cleared. The fix used here is to drain
+ * the prefetched but unused data from the data fifo until
+ * there is space for the input latch to drain.
*/
- mvi HADDR call dfdat_in_7;
- }
+ mov NONE, DFDAT;
+ test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
- /* Track odd'ness */
- test HCNT[0], 0x1 jz . + 2;
- xor DATA_COUNT_ODD, 0x1;
+ /* See if we have completed this last segment */
+ test STCNT[0], 0xff jnz data_phase_finish;
+ test STCNT[1], 0xff jnz data_phase_finish;
+ test STCNT[2], 0xff jnz data_phase_finish;
- if ((ahc->features & AHC_ULTRA2) == 0) {
- /* Load STCNT as well. It is a mirror of HCNT */
+ /*
+ * Advance the scatter-gather pointers if needed
+ */
+ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
+ or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
+ jmp data_phase_finish;
+sg_load:
+ /*
+ * Load the next SG element's data address and length
+ * into the DMA engine. If we don't have hardware
+ * to perform a prefetch, we'll have to fetch the
+ * segment from host memory first.
+ */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ /* Wait for the idle loop to complete */
+ test CCSGCTL, CCSGEN jz . + 3;
+ call idle_loop;
+ test CCSGCTL, CCSGEN jnz . - 1;
+ bmov HADDR, CCSGRAM, 7;
+ bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
bmov STCNT, HCNT, 3;
} else {
+ mvi DINDEX, HADDR;
+ mvi SCB_RESIDUAL_SGPTR call bcopy_4;
+
+ mvi SG_SIZEOF call set_hcnt;
+
+ or DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+ call dma_finish;
+
+ mvi HADDR call dfdat_in_7;
+ mov SCB_RESIDUAL_DATACNT[3], DFDAT;
call set_stcnt_from_hcnt;
}
- }
-/* Advance the SG pointer */
- clr A; /* add sizeof(struct scatter) */
- add SG_NEXT[0],SG_SIZEOF;
- adc SG_NEXT[1],A;
+ /* Track odd'ness */
+ test HCNT[0], 0x1 jz . + 2;
+ xor DATA_COUNT_ODD, 0x1;
+ /* Point to the new next sg in memory */
+ call sg_advance;
+
+ if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ test SSTAT0, TARGET jnz data_phase_loop;
+ }
+ }
+data_phase_finish:
+ /*
+ * If the target has left us in data phase, loop through
+ * the dma code again. In the case of ULTRA2 adapters,
+ * we should only loop if there is a data overrun. For
+ * all other adapters, we'll loop after each S/G element
+ * is loaded as well as if there is an overrun.
+ */
if ((ahc->flags & AHC_TARGETMODE) != 0) {
- test SSTAT0, TARGET jnz data_phase_loop;
+ test SSTAT0, TARGET jnz data_phase_done;
}
- test SSTAT1, REQINIT jz .;
- test SSTAT1,PHASEMIS jz data_phase_loop;
+ if ((ahc->flags & AHC_INITIATORMODE) != 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 .;
+ }
- /* Ensure the last seg is visable at the shaddow layer */
- if ((ahc->features & AHC_ULTRA2) != 0) {
- mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;/* Wait for preload to complete */
+ /*
+ * Turn off BITBUCKET mode and notify the host
+ * in the event of an overrun.
+ */
+ test SXFRCTL1,BITBUCKET jz data_phase_done;
+ and SXFRCTL1, ~BITBUCKET;
+ mvi INTSTAT,DATA_OVERRUN;
+ jmp ITloop;
}
-data_phase_finish:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- call ultra2_dmafinish;
- }
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes
- * were transferred on the SCSI (as opposed to the host) bus.
- */
+data_phase_done:
+ /*
+ * After a DMA finishes, save the SG and STCNT residuals back into
+ * the SCB. We use STCNT instead of HCNT, since it's a reflection
+ * of how many bytes were transferred on the SCSI (as opposed to the
+ * host) bus.
+ */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov SCB_RESID_DCNT, STCNT, 3;
+ /* Kill off any pending prefetch */
+ clr CCSGCTL;
+ test CCSGCTL, CCSGEN jnz .;
+
+ bmov SCB_RESIDUAL_DATACNT, STCNT, 3;
} else {
- mov SCB_RESID_DCNT[0],STCNT[0];
- mov SCB_RESID_DCNT[1],STCNT[1];
- mov SCB_RESID_DCNT[2],STCNT[2];
+ mov SCB_RESIDUAL_DATACNT[0],STCNT[0];
+ mov SCB_RESIDUAL_DATACNT[1],STCNT[1];
+ mov SCB_RESIDUAL_DATACNT[2],STCNT[2];
}
- mov SCB_RESID_SGCNT, SG_COUNT;
+
+ /*
+ * Since we've been through a data phase, the SCB_RESID* fields
+ * are now initialized. Clear the full residual flag.
+ */
+ and SCB_SGPTR[0], ~SG_FULL_RESID;
if ((ahc->features & AHC_ULTRA2) != 0) {
+ /* Clear the channel in case we return to data phase later */
or SXFRCTL0, CLRSTCNT|CLRCHN;
}
@@ -920,54 +1057,8 @@ data_phase_finish:
test DFCNTRL, DIRECTION jz target_ITloop;
test SSTAT1, REQINIT jnz .;
jmp target_ITloop;
- }
- jmp ITloop;
-
-data_phase_overrun:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- call ultra2_dmafinish;
- or SXFRCTL0, CLRSTCNT|CLRCHN;
- }
-/*
- * Turn off BITBUCKET mode and notify the host
- */
- and SXFRCTL1, ~BITBUCKET;
- mvi INTSTAT,DATA_OVERRUN;
- jmp ITloop;
-
-ultra2_dmafinish:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
- and DFCNTRL, ~SCSIEN;
- test DFCNTRL, SCSIEN jnz .;
-ultra2_dmafifoflush:
- or DFCNTRL, FIFOFLUSH;
- /*
- * The FIFOEMP status bit on the Ultra2 class
- * of controllers seems to be a bit flaky.
- * It appears that if the FIFO is full and the
- * transfer ends with some data in the REQ/ACK
- * FIFO, FIFOEMP will fall temporarily
- * as the data is transferred to the PCI bus.
- * This glitch lasts for fewer than 5 clock cycles,
- * so we work around the problem by ensuring the
- * status bit stays false through a full glitch
- * window.
- */
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-
-ultra2_dmafifoempty:
- /* Don't clobber an inprogress host data transfer */
- test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty;
-
-ultra2_dmahalt:
- and DFCNTRL, ~(SCSIEN|HDMAEN);
- test DFCNTRL, HDMAEN jnz .;
- ret;
+ } else {
+ jmp ITloop;
}
if ((ahc->flags & AHC_INITIATORMODE) != 0) {
@@ -977,48 +1068,61 @@ if ((ahc->flags & AHC_INITIATORMODE) != 0) {
p_command:
call assert;
- if ((ahc->features & AHC_CMD_CHAN) != 0) {
- mov HCNT[0], SCB_CMDLEN;
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ bmov HCNT[0], SCB_CDB_LEN, 1;
bmov HCNT[1], ALLZEROS, 2;
- if ((ahc->features & AHC_ULTRA2) == 0) {
- bmov STCNT, HCNT, 3;
- }
- add NONE, -17, SCB_CMDLEN;
- jc dma_cmd_data;
- /*
- * The data fifo seems to require 4 byte alligned
- * transfers from the sequencer. Force this to
- * be the case by clearing HADDR[0] even though
- * we aren't going to touch host memeory.
- */
- bmov HADDR[0], ALLZEROS, 1;
- if ((ahc->features & AHC_ULTRA2) != 0) {
- mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
- } else {
- mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
- }
- bmov DFDAT, SCB_CMDSTORE, 16;
- jmp cmd_loop;
-dma_cmd_data:
- bmov HADDR, SCB_CMDPTR, 4;
+ } else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ bmov STCNT[0], SCB_CDB_LEN, 1;
+ bmov STCNT[1], ALLZEROS, 2;
} else {
- mvi DINDEX, HADDR;
- mvi SCB_CMDPTR call bcopy_5;
- clr HCNT[1];
- clr HCNT[2];
+ mov STCNT[0], SCB_CDB_LEN;
+ clr STCNT[1];
+ clr STCNT[2];
}
-
- if ((ahc->features & AHC_ULTRA2) == 0) {
- if ((ahc->features & AHC_CMD_CHAN) == 0) {
- call set_stcnt_from_hcnt;
+ add NONE, -13, SCB_CDB_LEN;
+ mvi SCB_CDB_STORE jnc p_command_embedded;
+p_command_from_host:
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ bmov HADDR[0], SCB_CDB_PTR, 4;
+ mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+ } else {
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ bmov HADDR[0], SCB_CDB_PTR, 4;
+ bmov HCNT[0], STCNT[0], 3;
+ } else {
+ mvi DINDEX, HADDR;
+ mvi SCB_CDB_PTR call bcopy_5;
+ call clear_hcnt;
}
mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
+ }
+ jmp p_command_loop;
+p_command_embedded:
+ /*
+ * The data fifo seems to require 4 byte alligned
+ * transfers from the sequencer. Force this to
+ * be the case by clearing HADDR[0] even though
+ * we aren't going to touch host memeory.
+ */
+ clr HADDR[0];
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
} else {
- mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+ mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
+ }
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ bmov DFDAT, SCB_CDB_STORE, 12;
+ } else {
+ /*
+ * At most 12 bytes, but we copy 16 to fill
+ * the 64bit words in the FIFO
+ */
+ call copy_to_fifo_8;
+ call copy_to_fifo_8;
}
-cmd_loop:
+p_command_loop:
test SSTAT0, SDONE jnz . + 2;
- test SSTAT1, PHASEMIS jz cmd_loop;
+ test SSTAT1, PHASEMIS jz p_command_loop;
/*
* Wait for our ACK to go-away on it's own
* instead of being killed by SCSIEN getting cleared.
@@ -1035,7 +1139,7 @@ cmd_loop:
p_status:
call assert;
- mov SCB_TARGET_STATUS, SCSIDATL;
+ mov SCB_SCSI_STATUS, SCSIDATL;
jmp ITloop;
/*
@@ -1068,36 +1172,22 @@ p_mesgout:
mov SINDEX, MSG_OUT;
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
test SCB_CONTROL,MK_MESSAGE jnz host_message_loop;
- mov FUNCTION1, SCB_TCL;
+ mov FUNCTION1, SCB_SCSIID;
mov A, FUNCTION1;
- if ((ahc->features & AHC_HS_MAILBOX) != 0) {
- /*
- * Work around a pausing bug in at least the aic7890.
- * If the host needs to update the TARGET_MSG_REQUEST
- * bit field, it will set the HS_MAILBOX to 1. In
- * response, we pause with a specific interrupt code
- * asking for the mask to be updated before we continue.
- * Ugh.
- */
- test HS_MAILBOX, 0xF0 jz . + 2;
- mvi INTSTAT, UPDATE_TMSG_REQ;
- nop;
- }
mov SINDEX, TARGET_MSG_REQUEST[0];
if ((ahc->features & AHC_TWIN) != 0) {
/* Second Channel uses high byte bits */
- test SCB_TCL, SELBUSB jz . + 2;
+ test SCB_SCSIID, TWIN_CHNLB jz . + 2;
mov SINDEX, TARGET_MSG_REQUEST[1];
} else if ((ahc->features & AHC_WIDE) != 0) {
- test SCB_TCL, 0x80 jz . + 2; /* target > 7 */
+ test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */
mov SINDEX, TARGET_MSG_REQUEST[1];
}
test SINDEX, A jnz host_message_loop;
p_mesgout_identify:
- and SINDEX,LID,SCB_TCL; /* lun */
- and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
- or SINDEX,A; /* or in disconnect privledge */
- or SINDEX,MSG_IDENTIFYFLAG;
+ or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
+ test SCB_CONTROL, DISCENB jnz . + 2;
+ and SINDEX, ~DISCENB;
/*
* Send a tag message if TAG_ENB is set in the SCB control block.
* Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
@@ -1147,6 +1237,7 @@ p_mesgin:
cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs;
cmp ALLZEROS,A je mesgin_complete;
cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs;
+ cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue;
cmp A,MSG_NOOP je mesgin_done;
/*
@@ -1159,19 +1250,33 @@ p_mesgin:
* shouldn't hurt, but why do it twice...
*/
host_message_loop:
+ nop;
mvi INTSTAT, HOST_MSG_LOOP;
call phase_lock;
cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1;
jmp host_message_loop;
+mesgin_ign_wide_residue:
+if ((ahc->features & AHC_WIDE) != 0) {
+ test SCSIRATE, WIDEXFER jz mesgin_reject;
+ /* Pull the residue byte */
+ mvi ARG_1 call inb_next;
+ cmp ARG_1, 0x01 jne mesgin_reject;
+ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
+ test DATA_COUNT_ODD, 0x1 jz mesgin_done;
+ mvi INTSTAT, IGN_WIDE_RES;
+ jmp mesgin_done;
+}
+
+mesgin_reject:
+ mvi MSG_MESSAGE_REJECT call mk_mesg;
mesgin_done:
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
jmp ITloop;
-
mesgin_complete:
/*
- * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO,
* and trigger a completion interrupt. Before doing so, check to see if there
* is a residual or the status byte is something other than STATUS_GOOD (0).
* In either of these conditions, we upload the SCB back to the host so it can
@@ -1191,18 +1296,23 @@ mesgin_complete:
/*
* First check for residuals
*/
- test SCB_RESID_SGCNT,0xff jnz upload_scb;
- test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */
+ test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
+ test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
+ test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
+check_status:
+ test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */
upload_scb:
+ or SCB_SGPTR, SG_RESID_VALID;
mvi DMAPARAMS, FIFORESET;
mov SCB_TAG call dma_scb;
-check_status:
- test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */
- mvi INTSTAT,BAD_STATUS; /* let driver know */
- nop;
- cmp RETURN_1, SEND_SENSE jne complete;
- /* This SCB becomes the next to execute as it will retrieve sense */
+ test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */
+ mvi INTSTAT, BAD_STATUS; /* let driver know */
+ /*
+ * Prepare to DMA this SCB in case we are told to retrieve sense.
+ * Fills a delay slot after the INTSTAT as well.
+ */
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ cmp RETURN_1, SEND_SENSE jne complete;
mov SCB_TAG call dma_scb;
add_to_waiting_list:
mov SCB_NEXT,WAITING_SCBH;
@@ -1215,13 +1325,6 @@ add_to_waiting_list:
jmp await_busfree;
complete:
- /* If we are untagged, clear our address up in host ram */
- test SCB_CONTROL, TAG_ENB jnz complete_queue;
- mov A, SAVED_TCL;
- mvi UNTAGGEDSCB_OFFSET call post_byte_setup;
- mvi SCB_LIST_NULL call post_byte;
-
-complete_queue:
mov SCB_TAG call complete_post;
jmp await_busfree;
}
@@ -1245,11 +1348,20 @@ complete_post:
if ((ahc->flags & AHC_INITIATORMODE) != 0) {
/*
* Is it a disconnect message? Set a flag in the SCB to remind us
- * and await the bus going free.
+ * and await the bus going free. If this is an untagged transaction
+ * store the SCB id for it in our untagged target table for lookup on
+ * a reselction.
*/
mesgin_disconnect:
or SCB_CONTROL,DISCONNECTED;
- call add_scb_to_disc_list;
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ call add_scb_to_disc_list;
+ }
+ test SCB_CONTROL, TAG_ENB jnz await_busfree;
+ mov ARG_1, SCB_TAG;
+ mov SAVED_LUN, SCB_LUN;
+ mov SCB_SCSIID call index_busy_target;
+ mov DINDIR, ARG_1;
jmp await_busfree;
/*
@@ -1263,22 +1375,18 @@ mesgin_sdptrs:
test SEQ_FLAGS, DPHASE jz mesgin_done;
/*
- * The SCB SGPTR becomes the next one we'll download,
- * and the SCB DATAPTR becomes the current SHADDR.
+ * The SCB_SGPTR becomes the next one we'll download,
+ * and the SCB_DATAPTR becomes the current SHADDR.
* Use the residual number since STCNT is corrupted by
* any message transfer.
*/
if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov SCB_SGCOUNT, SG_COUNT, 5;
bmov SCB_DATAPTR, SHADDR, 4;
- bmov SCB_DATACNT, SCB_RESID_DCNT, 3;
+ bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
} else {
- mvi DINDEX, SCB_SGCOUNT;
- mvi SG_COUNT call bcopy_5;
-
mvi DINDEX, SCB_DATAPTR;
- mvi SHADDR call bcopy_4;
- mvi SCB_RESID_DCNT call bcopy_3;
+ mvi SHADDR call bcopy_4;
+ mvi SCB_RESIDUAL_DATACNT call bcopy_8;
}
jmp mesgin_done;
@@ -1297,39 +1405,55 @@ mesgin_rdptrs:
jmp mesgin_done;
/*
+ * Index into our Busy Target table. SINDEX and DINDEX are modified
+ * upon return. SCBPTR may be modified by this action.
+ */
+index_busy_target:
+ if ((ahc->features & AHC_SCB_BTT) != 0) {
+ mov SCBPTR, SAVED_LUN;
+ add SINDEX, SCB_64_BTT;
+ } else {
+ shr SINDEX, 4;
+ add SINDEX, BUSY_TARGETS;
+ }
+ mov DINDEX, SINDEX ret;
+
+/*
* Identify message? For a reconnecting target, this tells us the lun
* that the reconnection is for - find the correct SCB and switch to it,
* clearing the "disconnected" bit so we don't "find" it by accident later.
*/
mesgin_identify:
- if ((ahc->features & AHC_WIDE) != 0) {
- and A,0x0f; /* lun in lower four bits */
+ and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
+ /*
+ * Determine whether a target is using tagged or non-tagged
+ * transactions by first looking at the transaction stored in
+ * the busy target array. If there is no untagged transaction
+ * for this target or the transaction is for a different lun, then
+ * this must be an untagged transaction.
+ */
+ mov SAVED_SCSIID call index_busy_target;
+ mov A, SINDIR;
+ cmp A, SCB_LIST_NULL je snoop_tag;
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ mov A call findSCB;
} else {
- and A,0x07; /* lun in lower three bits */
+ mov SCBPTR, A;
}
- or SAVED_TCL,A; /* SAVED_TCL should be complete now */
-
- mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */
- call get_untagged_SCBID;
- cmp ARG_1, SCB_LIST_NULL je snoop_tag;
- if ((ahc->flags & AHC_PAGESCBS) != 0) {
- test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
+ if ((ahc->features & AHC_SCB_BTT) != 0) {
+ jmp setup_SCB_id_lun_okay;
+ } else {
+ mov A, SCB_LUN;
+ cmp SAVED_LUN, A je setup_SCB_id_lun_okay;
}
- /*
- * If the SCB was found in the disconnected list (as is
- * always the case in non-paging scenarios), SCBPTR is already
- * set to the correct SCB. So, simply setup the SCB and get
- * on with things.
- */
- call rem_scb_from_disc_list;
- jmp setup_SCB;
+
/*
* Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
* If we get one, we use the tag returned to find the proper
- * SCB. With SCB paging, this requires using search for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
+ * SCB. With SCB paging, we must search for non-tagged
+ * transactions since the SCB may exist in any slot. If we're not
+ * using SCB paging, we can use the tag as the direct index to the
+ * SCB.
*/
snoop_tag:
mov NONE,SCSIDATL; /* ACK Identify MSG */
@@ -1338,20 +1462,35 @@ snoop_tag_loop:
cmp LASTPHASE, P_MESGIN jne not_found;
cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
get_tag:
- mvi ARG_1 call inb_next; /* tag value */
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ mvi ARG_1 call inb_next; /* tag value */
+ mov ARG_1 call findSCB;
+ } else {
+ mvi SCBPTR call inb_next; /* tag value */
+ }
- /*
- * Ensure that the SCB the tag points to is for
- * an SCB transaction to the reconnecting target.
- */
-use_retrieveSCB:
- call retrieveSCB;
+/*
+ * Ensure that the SCB the tag points to is for
+ * an SCB transaction to the reconnecting target.
+ */
setup_SCB:
- mov A, SAVED_TCL;
- cmp SCB_TCL, A jne not_found_cleanup_scb;
- test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
+ mov A, SAVED_SCSIID;
+ cmp SCB_SCSIID, A jne not_found;
+ mov A, SAVED_LUN;
+ cmp SCB_LUN, A jne not_found;
+setup_SCB_id_lun_okay:
+ test SCB_CONTROL,DISCONNECTED jz not_found;
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ mov SCBPTR call rem_scb_from_disc_list;
+ }
and SCB_CONTROL,~DISCONNECTED;
or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
+ test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged;
+ mov A, SCBPTR;
+ mov SAVED_SCSIID call index_busy_target;
+ mvi DINDIR, SCB_LIST_NULL;
+ mov SCBPTR, A;
+setup_SCB_tagged:
call set_transfer_settings;
/* See if the host wants to send a message upon reconnection */
test SCB_CONTROL, MK_MESSAGE jz mesgin_done;
@@ -1359,23 +1498,10 @@ setup_SCB:
mvi HOST_MSG call mk_mesg;
jmp mesgin_done;
-not_found_cleanup_scb:
- test SCB_CONTROL, DISCONNECTED jz . + 3;
- call add_scb_to_disc_list;
- jmp not_found;
- call add_scb_to_free_list;
not_found:
mvi INTSTAT, NO_MATCH;
jmp mesgin_done;
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already. SINDEX is returned intact.
- */
mk_mesg:
or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
mov MSG_OUT,SINDEX ret;
@@ -1435,7 +1561,7 @@ change_phase:
/*
* If the data direction has changed, from
* out (initiator driving) to in (target driving),
- * we must waitat least a data release delay plus
+ * we must wait at least a data release delay plus
* the normal bus settle delay. [SCSI III SPI 10.11.0]
*/
cmp DINDEX, A je change_phase_wait;
@@ -1458,62 +1584,6 @@ target_outb:
and SXFRCTL0, ~SPIOEN ret;
}
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
- mvi INTSTAT, MSGIN_PHASEMIS;
- jmp ITloop;
-
-/*
- * DMA data transfer. HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
- * during initialization.
- */
-dma:
- mov DFCNTRL,SINDEX;
-dma_loop:
- test SSTAT0,DMADONE jnz dma_dmadone;
- test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */
-dma_phasemis:
-
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma_checkfifo:
- test DFCNTRL,DIRECTION jnz dma_fifoempty;
-dma_fifoflush:
- test DFSTATUS,FIFOEMP jz dma_fifoflush;
-
-dma_fifoempty:
- /* Don't clobber an inprogress host data transfer */
- test DFSTATUS, MREQPEND jnz dma_fifoempty;
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are
- * actually off first lest we get an ILLSADDR.
- */
-dma_dmadone:
- and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
-dma_halt:
- /*
- * Some revisions of the aic7880 have a problem where, if the
- * data fifo is full, but the PCI input latch is not empty,
- * HDMAEN cannot be cleared. The fix used here is to attempt
- * to drain the data fifo until there is space for the input
- * latch to drain and HDMAEN de-asserts.
- */
- if ((ahc->features & AHC_ULTRA2) == 0) {
- mov NONE, DFDAT;
- }
- test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
-return:
- ret;
/*
* Assert that if we've been reselected, then we've seen an IDENTIFY
@@ -1525,42 +1595,37 @@ assert:
mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */
/*
- * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBID ARG_1. The search begins at the SCB index passed in
- * via SINDEX which is an SCB that must be on the disconnected list. If
- * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
- * is set to the proper SCB.
+ * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will
+ * be set to the position of the SCB. If the SCB cannot be found locally,
+ * it will be paged in from host memory. RETURN_2 stores the address of the
+ * preceding SCB in the disconnected list which can be used to speed up
+ * removal of the found SCB from the disconnected list.
*/
findSCB:
- mov SCBPTR,SINDEX; /* Initialize SCBPTR */
- cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID;
- mov A, SAVED_TCL;
- mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */
-findSCB_by_SCBID:
- mov A, ARG_1; /* Tag passed in ARG_1 */
- mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */
+ mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */
+ mov A, SINDEX; /* Tag passed in SINDEX */
+ mvi RETURN_2, SCB_LIST_NULL; /* Head of list */
+ jmp findSCB_loop;
findSCB_next:
- mov ARG_2, SCBPTR;
- cmp SCB_NEXT, SCB_LIST_NULL je notFound;
+ mov RETURN_2, SCBPTR;
+ cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
mov SCBPTR,SCB_NEXT;
- dec SINDEX; /* Last comparison moved us too far */
findSCB_loop:
- cmp SINDIR, A jne findSCB_next;
+ cmp SCB_TAG, A jne findSCB_next;
mov SINDEX, SCBPTR ret;
-notFound:
- mvi SINDEX, SCB_LIST_NULL ret;
-
-/*
- * Retrieve an SCB by SCBID first searching the disconnected list falling
- * back to DMA'ing the SCB down from the host. This routine assumes that
- * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
- * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL,
- * we go directly to the host for the SCB.
- */
-retrieveSCB:
- test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host;
- mov SCBPTR call findSCB; /* Continue the search */
- cmp SINDEX, SCB_LIST_NULL je retrieve_from_host;
+findSCB_notFound:
+ /*
+ * We didn't find it. Page in the SCB and make it look
+ * like it was at the head of the appropriate scb list.
+ */
+ mov ARG_1, A; /* Save tag */
+ mov ALLZEROS call get_free_or_disc_scb;
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov ARG_1 call dma_scb;
+ mvi RETURN_2, SCB_LIST_NULL; /* Head of list */
+ /* Jump instead of call as we want to return anyway */
+ test SCB_CONTROL, DISCONNECTED jnz add_scb_to_disc_list;
+ jmp add_scb_to_free_list;
/*
* This routine expects SINDEX to contain the index of the SCB to be
@@ -1578,44 +1643,15 @@ rem_scb_from_disc_list:
rHead:
mov DISCONNECTED_SCBH,SCB_NEXT ret;
-retrieve_from_host:
-/*
- * We didn't find it. Pull an SCB and DMA down the one we want.
- * We should never get here in the non-paging case.
- */
- mov ALLZEROS call get_free_or_disc_scb;
- mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- /* Jump instead of call as we want to return anyway */
- mov ARG_1 jmp dma_scb;
-
-/*
- * Determine whether a target is using tagged or non-tagged transactions
- * by first looking for a matching transaction based on the TCL and if
- * that fails, looking up this device in the host's untagged SCB array.
- * The TCL to search for is assumed to be in SAVED_TCL. The value is
- * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
- * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
- * in an SCB instead of having to go to the host.
- */
-get_untagged_SCBID:
- cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
- mvi ARG_1, SCB_LIST_NULL;
- mov DISCONNECTED_SCBH call findSCB;
- cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host;
- or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
- test SCB_CONTROL, TAG_ENB jnz . + 2;
- mov ARG_1, SCB_TAG ret;
- mvi ARG_1, SCB_LIST_NULL ret;
-
/*
* Fetch a byte from host memory given an index of (A + (256 * SINDEX))
- * and a base address of SCBID_ADDR. The byte is returned in RETURN_2.
+ * and a base address of SHARED_DATA_ADDR. The byte is returned in RETURN_2.
*/
fetch_byte:
mov ARG_2, SINDEX;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi DINDEX, CCHADDR;
- mvi SCBID_ADDR call set_1byte_addr;
+ mvi SHARED_DATA_ADDR call set_1byte_addr;
mvi CCHCNT, 1;
mvi CCSGCTL, CCSGEN|CCSGRESET;
test CCSGCTL, CCSGDONE jz .;
@@ -1623,10 +1659,8 @@ fetch_byte:
bmov RETURN_2, CCSGRAM, 1 ret;
} else {
mvi DINDEX, HADDR;
- mvi SCBID_ADDR call set_1byte_addr;
- mvi HCNT[0], 1;
- clr HCNT[1];
- clr HCNT[2];
+ mvi SHARED_DATA_ADDR call set_1byte_addr;
+ mvi 1 call set_hcnt;
mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
call dma_finish;
mov RETURN_2, DFDAT ret;
@@ -1634,21 +1668,19 @@ fetch_byte:
/*
* Prepare the hardware to post a byte to host memory given an
- * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
+ * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
*/
post_byte_setup:
mov ARG_2, SINDEX;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi DINDEX, CCHADDR;
- mvi SCBID_ADDR call set_1byte_addr;
+ mvi SHARED_DATA_ADDR call set_1byte_addr;
mvi CCHCNT, 1;
mvi CCSCBCTL, CCSCBRESET ret;
} else {
mvi DINDEX, HADDR;
- mvi SCBID_ADDR call set_1byte_addr;
- mvi HCNT[0], 1;
- clr HCNT[1];
- clr HCNT[2];
+ mvi SHARED_DATA_ADDR call set_1byte_addr;
+ mvi 1 call set_hcnt;
mvi DFCNTRL, FIFORESET ret;
}
@@ -1665,8 +1697,9 @@ post_byte:
}
get_SCBID_from_host:
- mov A, SAVED_TCL;
- mvi UNTAGGEDSCB_OFFSET call fetch_byte;
+ mov A, SAVED_LUN;
+ shr SINDEX, 4, SAVED_SCSIID;
+ call fetch_byte;
mov RETURN_1, RETURN_2 ret;
phase_lock_perr:
@@ -1684,11 +1717,19 @@ phase_lock_latch_phase:
and LASTPHASE, PHASE_MASK, SCSISIGI ret;
if ((ahc->features & AHC_CMD_CHAN) == 0) {
+set_hcnt:
+ mov HCNT[0], SINDEX;
+clear_hcnt:
+ clr HCNT[1];
+ clr HCNT[2] ret;
+
set_stcnt_from_hcnt:
mov STCNT[0], HCNT[0];
mov STCNT[1], HCNT[1];
mov STCNT[2], HCNT[2] ret;
+bcopy_8:
+ mov DINDIR, SINDIR;
bcopy_7:
mov DINDIR, SINDIR;
mov DINDIR, SINDIR;
@@ -1728,7 +1769,7 @@ set_64byte_addr:
shl A, 6;
/*
- * Setup addr assuming that A + (ARG_1 * 256) is an
+ * Setup addr assuming that A + (ARG_2 * 256) is an
* index into an array of 1byte objects, SINDEX contains
* the base address of that array, and DINDEX contains
* the base address of the location to store the computed
@@ -1775,9 +1816,7 @@ dma_scb_finish:
} else {
mvi DINDEX, HADDR;
mvi HSCB_ADDR call set_64byte_addr;
- mvi HCNT[0], SCB_32BYTE_SIZE;
- clr HCNT[1];
- clr HCNT[2];
+ mvi SCB_32BYTE_SIZE call set_hcnt;
mov DFCNTRL, DMAPARAMS;
test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
/* Fill it with the SCB data */
@@ -1785,13 +1824,7 @@ copy_scb_tofifo:
mvi SINDEX, SCB_CONTROL;
add A, SCB_32BYTE_SIZE, SINDEX;
copy_scb_tofifo_loop:
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
- mov DFDAT,SINDIR;
+ call copy_to_fifo_6;
cmp SINDEX, A jne copy_scb_tofifo_loop;
or DFCNTRL, HDMAEN|FIFOFLUSH;
dma_scb_fromhost:
@@ -1801,7 +1834,8 @@ dma_scb_fromhost:
mvi SCB_CONTROL call dfdat_in_7;
call dfdat_in_7_continued;
call dfdat_in_7_continued;
- jmp dfdat_in_7_continued;
+ call dfdat_in_7_continued;
+ jmp dfdat_in_2_continued;
dfdat_in_7:
mov DINDEX,SINDEX;
dfdat_in_7_continued:
@@ -1810,10 +1844,24 @@ dfdat_in_7_continued:
mov DINDIR,DFDAT;
mov DINDIR,DFDAT;
mov DINDIR,DFDAT;
+dfdat_in_2_continued:
mov DINDIR,DFDAT;
mov DINDIR,DFDAT ret;
}
+copy_to_fifo_8:
+ mov DFDAT,SINDIR;
+copy_to_fifo_7:
+ mov DFDAT,SINDIR;
+copy_to_fifo_6:
+ mov DFDAT,SINDIR;
+copy_to_fifo_5:
+ mov DFDAT,SINDIR;
+copy_to_fifo_4:
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR ret;
/*
* Wait for DMA from host memory to data FIFO to complete, then disable
@@ -1861,3 +1909,5 @@ add_scb_to_disc_list:
*/
mov SCB_NEXT, DISCONNECTED_SCBH;
mov DISCONNECTED_SCBH, SCBPTR ret;
+return:
+ ret;
diff --git a/sys/dev/aic7xxx/aic7xxx_93cx6.c b/sys/dev/aic7xxx/aic7xxx_93cx6.c
index 06e547b..62a4aee 100644
--- a/sys/dev/aic7xxx/aic7xxx_93cx6.c
+++ b/sys/dev/aic7xxx/aic7xxx_93cx6.c
@@ -89,14 +89,14 @@ static struct seeprom_cmd {
int
read_seeprom(sd, buf, start_addr, count)
struct seeprom_descriptor *sd;
- u_int16_t *buf;
+ uint16_t *buf;
bus_size_t start_addr;
bus_size_t count;
{
int i = 0;
u_int k = 0;
- u_int16_t v;
- u_int8_t temp;
+ uint16_t v;
+ uint8_t temp;
/*
* Read the requested registers of the seeprom. The loop
diff --git a/sys/dev/aic7xxx/aic7xxx_93cx6.h b/sys/dev/aic7xxx/aic7xxx_93cx6.h
index 7875032..8fd7bb9 100644
--- a/sys/dev/aic7xxx/aic7xxx_93cx6.h
+++ b/sys/dev/aic7xxx/aic7xxx_93cx6.h
@@ -16,7 +16,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -52,12 +52,12 @@ struct seeprom_descriptor {
bus_size_t sd_status_offset;
bus_size_t sd_dataout_offset;
seeprom_chip_t sd_chip;
- u_int16_t sd_MS;
- u_int16_t sd_RDY;
- u_int16_t sd_CS;
- u_int16_t sd_CK;
- u_int16_t sd_DO;
- u_int16_t sd_DI;
+ uint16_t sd_MS;
+ uint16_t sd_RDY;
+ uint16_t sd_CS;
+ uint16_t sd_CK;
+ uint16_t sd_DO;
+ uint16_t sd_DI;
};
/*
@@ -85,7 +85,7 @@ struct seeprom_descriptor {
#define SEEPROM_DATA_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
-int read_seeprom(struct seeprom_descriptor *sd, u_int16_t *buf,
+int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
bus_size_t start_addr, bus_size_t count);
#endif /* _KERNEL */
diff --git a/sys/dev/aic7xxx/aicasm.c b/sys/dev/aic7xxx/aicasm.c
index 9af5c83..374e86c 100644
--- a/sys/dev/aic7xxx/aicasm.c
+++ b/sys/dev/aic7xxx/aicasm.c
@@ -1,7 +1,7 @@
/*
* Aic7xxx SCSI host adapter firmware asssembler
*
- * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -39,7 +42,7 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
-#include "sequencer.h"
+#include "aicasm_insformat.h"
typedef struct patch {
STAILQ_ENTRY(patch) links;
@@ -53,8 +56,8 @@ STAILQ_HEAD(patch_list, patch) patches;
static void usage(void);
static void back_patch(void);
-static void output_code(FILE *ofile);
-static void output_listing(FILE *listfile, char *ifilename);
+static void output_code(void);
+static void output_listing(char *ifilename);
static void dump_scope(scope_t *scope);
static void emit_patch(scope_t *scope, int patch);
static int check_patch(patch_t **start_patch, int start_instr,
@@ -238,12 +241,12 @@ main(argc, argv)
back_patch();
if (ofile != NULL)
- output_code(ofile);
+ output_code();
if (regfile != NULL) {
symtable_dump(regfile);
}
if (listfile != NULL)
- output_listing(listfile, inputfilename);
+ output_listing(inputfilename);
}
stop(NULL, 0);
@@ -293,8 +296,7 @@ back_patch()
}
static void
-output_code(ofile)
- FILE *ofile;
+output_code()
{
struct instruction *cur_instr;
patch_t *cur_patch;
@@ -307,16 +309,23 @@ output_code(ofile)
* DO NOT EDIT - This file is automatically generated.
*/\n");
- fprintf(ofile, "static u_int8_t seqprog[] = {\n");
+ fprintf(ofile, "static uint8_t seqprog[] = {\n");
for(cur_instr = seq_program.stqh_first;
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next) {
fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+#if BYTE_ORDER == LITTLE_ENDIAN
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
+#else
+ cur_instr->format.bytes[3],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[0]);
+#endif
instrcount++;
}
fprintf(ofile, "};\n\n");
@@ -344,7 +353,7 @@ ahc_patch%d_func(struct ahc_softc *ahc)
"typedef int patch_func_t __P((struct ahc_softc *));
struct patch {
patch_func_t *patch_func;
- u_int32_t begin :10,
+ uint32_t begin :10,
skip_instr :10,
skip_patch :12;
} patches[] = {\n");
@@ -422,7 +431,7 @@ emit_patch(scope_t *scope, int patch)
}
void
-output_listing(FILE *listfile, char *ifilename)
+output_listing(char *ifilename)
{
char buf[1024];
FILE *ifile;
@@ -517,10 +526,17 @@ output_listing(FILE *listfile, char *ifilename)
line++;
}
fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
+#if BYTE_ORDER == LITTLE_ENDIAN
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
+#else
+ cur_instr->format.bytes[3],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[0]);
+#endif
fgets(buf, sizeof(buf), ifile);
fprintf(listfile, "\t%s", buf);
line++;
diff --git a/sys/dev/aic7xxx/aicasm.h b/sys/dev/aic7xxx/aicasm.h
index 7e6b468..9faecd0 100644
--- a/sys/dev/aic7xxx/aicasm.h
+++ b/sys/dev/aic7xxx/aicasm.h
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
diff --git a/sys/dev/aic7xxx/aicasm/aicasm.c b/sys/dev/aic7xxx/aicasm/aicasm.c
index 9af5c83..374e86c 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm.c
+++ b/sys/dev/aic7xxx/aicasm/aicasm.c
@@ -1,7 +1,7 @@
/*
* Aic7xxx SCSI host adapter firmware asssembler
*
- * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -39,7 +42,7 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
-#include "sequencer.h"
+#include "aicasm_insformat.h"
typedef struct patch {
STAILQ_ENTRY(patch) links;
@@ -53,8 +56,8 @@ STAILQ_HEAD(patch_list, patch) patches;
static void usage(void);
static void back_patch(void);
-static void output_code(FILE *ofile);
-static void output_listing(FILE *listfile, char *ifilename);
+static void output_code(void);
+static void output_listing(char *ifilename);
static void dump_scope(scope_t *scope);
static void emit_patch(scope_t *scope, int patch);
static int check_patch(patch_t **start_patch, int start_instr,
@@ -238,12 +241,12 @@ main(argc, argv)
back_patch();
if (ofile != NULL)
- output_code(ofile);
+ output_code();
if (regfile != NULL) {
symtable_dump(regfile);
}
if (listfile != NULL)
- output_listing(listfile, inputfilename);
+ output_listing(inputfilename);
}
stop(NULL, 0);
@@ -293,8 +296,7 @@ back_patch()
}
static void
-output_code(ofile)
- FILE *ofile;
+output_code()
{
struct instruction *cur_instr;
patch_t *cur_patch;
@@ -307,16 +309,23 @@ output_code(ofile)
* DO NOT EDIT - This file is automatically generated.
*/\n");
- fprintf(ofile, "static u_int8_t seqprog[] = {\n");
+ fprintf(ofile, "static uint8_t seqprog[] = {\n");
for(cur_instr = seq_program.stqh_first;
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next) {
fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+#if BYTE_ORDER == LITTLE_ENDIAN
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
+#else
+ cur_instr->format.bytes[3],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[0]);
+#endif
instrcount++;
}
fprintf(ofile, "};\n\n");
@@ -344,7 +353,7 @@ ahc_patch%d_func(struct ahc_softc *ahc)
"typedef int patch_func_t __P((struct ahc_softc *));
struct patch {
patch_func_t *patch_func;
- u_int32_t begin :10,
+ uint32_t begin :10,
skip_instr :10,
skip_patch :12;
} patches[] = {\n");
@@ -422,7 +431,7 @@ emit_patch(scope_t *scope, int patch)
}
void
-output_listing(FILE *listfile, char *ifilename)
+output_listing(char *ifilename)
{
char buf[1024];
FILE *ifile;
@@ -517,10 +526,17 @@ output_listing(FILE *listfile, char *ifilename)
line++;
}
fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
+#if BYTE_ORDER == LITTLE_ENDIAN
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
+#else
+ cur_instr->format.bytes[3],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[0]);
+#endif
fgets(buf, sizeof(buf), ifile);
fprintf(listfile, "\t%s", buf);
line++;
diff --git a/sys/dev/aic7xxx/aicasm/aicasm.h b/sys/dev/aic7xxx/aicasm/aicasm.h
index 7e6b468..9faecd0 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm.h
+++ b/sys/dev/aic7xxx/aicasm/aicasm.h
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_gram.y b/sys/dev/aic7xxx/aicasm/aicasm_gram.y
index 4d09059..5731f67 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm_gram.y
+++ b/sys/dev/aic7xxx/aicasm/aicasm_gram.y
@@ -2,7 +2,7 @@
/*
* Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
*
- * Copyright (c) 1997-1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,6 +14,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -39,7 +42,7 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
-#include "sequencer.h"
+#include "aicasm_insformat.h"
int yylineno;
char *yyfilename;
@@ -130,7 +133,7 @@ static int is_download_const __P((expression_t *immed));
%token <value> T_STC T_CLC
-%token <value> T_CMP T_XOR
+%token <value> T_CMP T_NOT T_XOR
%token <value> T_TEST T_AND
@@ -551,6 +554,21 @@ reg_symbol:
$$.symbol = $1;
$$.offset = 0;
}
+| T_SYMBOL '[' T_SYMBOL ']'
+ {
+ process_register(&$1);
+ if ($3->type != CONST) {
+ stop("register offset must be a constant", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
+ stop("Accessing offset beyond range of register",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = $1;
+ $$.offset = $3->info.cinfo->value;
+ }
| T_SYMBOL '[' T_NUMBER ']'
{
process_register(&$1);
@@ -827,7 +845,7 @@ code:
;
code:
- T_BMOV destination ',' source ',' immediate ret ';'
+ T_BMOV destination ',' source ',' immediate_or_a ret ';'
{
format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
}
@@ -851,6 +869,16 @@ code:
;
code:
+ T_NOT destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
T_CLR destination ret ';'
{
expression_t immed;
@@ -1173,7 +1201,7 @@ format_2_instr(opcode, dest, places, src, ret)
{
struct instruction *instr;
struct ins_format2 *f2_instr;
- u_int8_t shift_control;
+ uint8_t shift_control;
if (src->symbol == NULL)
src = dest;
diff --git a/sys/dev/aic7xxx/sequencer.h b/sys/dev/aic7xxx/aicasm/aicasm_insformat.h
index 4f05491..6466747 100644
--- a/sys/dev/aic7xxx/sequencer.h
+++ b/sys/dev/aic7xxx/aicasm/aicasm_insformat.h
@@ -2,7 +2,7 @@
* Instruction formats for the sequencer program downloaded to
* Aic7xxx SCSI host adapters
*
- * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -15,7 +15,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * the GNU Public License ("GPL").
+ * GNU Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -32,38 +32,66 @@
* $FreeBSD$
*/
+#include <machine/endian.h>
+
struct ins_format1 {
- u_int32_t immediate : 8,
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t immediate : 8,
source : 9,
destination : 9,
ret : 1,
opcode : 4,
parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ ret : 1,
+ destination : 9,
+ source : 9,
+ immediate : 8;
+#endif
};
struct ins_format2 {
- u_int32_t shift_control : 8,
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t shift_control : 8,
source : 9,
destination : 9,
ret : 1,
opcode : 4,
parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ ret : 1,
+ destination : 9,
+ source : 9,
+ shift_control : 8;
+#endif
};
struct ins_format3 {
- u_int32_t immediate : 8,
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t immediate : 8,
source : 9,
address : 10,
opcode : 4,
parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ address : 10,
+ source : 9,
+ immediate : 8;
+#endif
};
union ins_formats {
struct ins_format1 format1;
struct ins_format2 format2;
struct ins_format3 format3;
- u_int8_t bytes[4];
- u_int32_t integer;
+ uint8_t bytes[4];
+ uint32_t integer;
};
struct instruction {
union ins_formats format;
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_scan.l b/sys/dev/aic7xxx/aicasm/aicasm_scan.l
index 28689cb..48170d6 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm_scan.l
+++ b/sys/dev/aic7xxx/aicasm/aicasm_scan.l
@@ -2,7 +2,7 @@
/*
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
*
- * Copyright (c) 1997-1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,6 +14,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -145,6 +148,7 @@ dec { return T_DEC; }
stc { return T_STC; }
clc { return T_CLC; }
cmp { return T_CMP; }
+not { return T_NOT; }
xor { return T_XOR; }
test { return T_TEST;}
and { return T_AND; }
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
index 8c250d2..43440ea 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
+++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -397,7 +400,7 @@ symtable_dump(ofile)
*/\n");
while (registers.slh_first != NULL) {
symbol_node_t *curnode;
- u_int8_t value;
+ uint8_t value;
char *tab_str;
char *tab_str2;
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.h b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h
index 79809db..37f5e7f 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm_symbol.h
+++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -51,10 +54,10 @@ typedef enum {
}amode_t;
struct reg_info {
- u_int8_t address;
+ uint8_t address;
int size;
amode_t mode;
- u_int8_t valid_bitmask;
+ uint8_t valid_bitmask;
int typecheck_masks;
};
@@ -62,11 +65,11 @@ typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
struct mask_info {
symlist_t symrefs;
- u_int8_t mask;
+ uint8_t mask;
};
struct const_info {
- u_int8_t value;
+ uint8_t value;
int define;
};
diff --git a/sys/dev/aic7xxx/aicasm_gram.y b/sys/dev/aic7xxx/aicasm_gram.y
index 4d09059..5731f67 100644
--- a/sys/dev/aic7xxx/aicasm_gram.y
+++ b/sys/dev/aic7xxx/aicasm_gram.y
@@ -2,7 +2,7 @@
/*
* Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
*
- * Copyright (c) 1997-1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,6 +14,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -39,7 +42,7 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
-#include "sequencer.h"
+#include "aicasm_insformat.h"
int yylineno;
char *yyfilename;
@@ -130,7 +133,7 @@ static int is_download_const __P((expression_t *immed));
%token <value> T_STC T_CLC
-%token <value> T_CMP T_XOR
+%token <value> T_CMP T_NOT T_XOR
%token <value> T_TEST T_AND
@@ -551,6 +554,21 @@ reg_symbol:
$$.symbol = $1;
$$.offset = 0;
}
+| T_SYMBOL '[' T_SYMBOL ']'
+ {
+ process_register(&$1);
+ if ($3->type != CONST) {
+ stop("register offset must be a constant", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
+ stop("Accessing offset beyond range of register",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = $1;
+ $$.offset = $3->info.cinfo->value;
+ }
| T_SYMBOL '[' T_NUMBER ']'
{
process_register(&$1);
@@ -827,7 +845,7 @@ code:
;
code:
- T_BMOV destination ',' source ',' immediate ret ';'
+ T_BMOV destination ',' source ',' immediate_or_a ret ';'
{
format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
}
@@ -851,6 +869,16 @@ code:
;
code:
+ T_NOT destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
T_CLR destination ret ';'
{
expression_t immed;
@@ -1173,7 +1201,7 @@ format_2_instr(opcode, dest, places, src, ret)
{
struct instruction *instr;
struct ins_format2 *f2_instr;
- u_int8_t shift_control;
+ uint8_t shift_control;
if (src->symbol == NULL)
src = dest;
diff --git a/sys/dev/aic7xxx/aicasm_insformat.h b/sys/dev/aic7xxx/aicasm_insformat.h
new file mode 100644
index 0000000..6466747
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm_insformat.h
@@ -0,0 +1,123 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/endian.h>
+
+struct ins_format1 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t immediate : 8,
+ source : 9,
+ destination : 9,
+ ret : 1,
+ opcode : 4,
+ parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ ret : 1,
+ destination : 9,
+ source : 9,
+ immediate : 8;
+#endif
+};
+
+struct ins_format2 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t shift_control : 8,
+ source : 9,
+ destination : 9,
+ ret : 1,
+ opcode : 4,
+ parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ ret : 1,
+ destination : 9,
+ source : 9,
+ shift_control : 8;
+#endif
+};
+
+struct ins_format3 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t immediate : 8,
+ source : 9,
+ address : 10,
+ opcode : 4,
+ parity : 1;
+#else
+ uint32_t parity : 1,
+ opcode : 4,
+ address : 10,
+ source : 9,
+ immediate : 8;
+#endif
+};
+
+union ins_formats {
+ struct ins_format1 format1;
+ struct ins_format2 format2;
+ struct ins_format3 format3;
+ uint8_t bytes[4];
+ uint32_t integer;
+};
+struct instruction {
+ union ins_formats format;
+ u_int srcline;
+ struct symbol *patch_label;
+ STAILQ_ENTRY(instruction) links;
+};
+
+#define AIC_OP_OR 0x0
+#define AIC_OP_AND 0x1
+#define AIC_OP_XOR 0x2
+#define AIC_OP_ADD 0x3
+#define AIC_OP_ADC 0x4
+#define AIC_OP_ROL 0x5
+#define AIC_OP_BMOV 0x6
+
+#define AIC_OP_JMP 0x8
+#define AIC_OP_JC 0x9
+#define AIC_OP_JNC 0xa
+#define AIC_OP_CALL 0xb
+#define AIC_OP_JNE 0xc
+#define AIC_OP_JNZ 0xd
+#define AIC_OP_JE 0xe
+#define AIC_OP_JZ 0xf
+
+/* Pseudo Ops */
+#define AIC_OP_SHL 0x10
+#define AIC_OP_SHR 0x20
+#define AIC_OP_ROR 0x30
diff --git a/sys/dev/aic7xxx/aicasm_scan.l b/sys/dev/aic7xxx/aicasm_scan.l
index 28689cb..48170d6 100644
--- a/sys/dev/aic7xxx/aicasm_scan.l
+++ b/sys/dev/aic7xxx/aicasm_scan.l
@@ -2,7 +2,7 @@
/*
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
*
- * Copyright (c) 1997-1998 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,6 +14,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -145,6 +148,7 @@ dec { return T_DEC; }
stc { return T_STC; }
clc { return T_CLC; }
cmp { return T_CMP; }
+not { return T_NOT; }
xor { return T_XOR; }
test { return T_TEST;}
and { return T_AND; }
diff --git a/sys/dev/aic7xxx/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm_symbol.c
index 8c250d2..43440ea 100644
--- a/sys/dev/aic7xxx/aicasm_symbol.c
+++ b/sys/dev/aic7xxx/aicasm_symbol.c
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -397,7 +400,7 @@ symtable_dump(ofile)
*/\n");
while (registers.slh_first != NULL) {
symbol_node_t *curnode;
- u_int8_t value;
+ uint8_t value;
char *tab_str;
char *tab_str2;
diff --git a/sys/dev/aic7xxx/aicasm_symbol.h b/sys/dev/aic7xxx/aicasm_symbol.h
index 79809db..37f5e7f 100644
--- a/sys/dev/aic7xxx/aicasm_symbol.h
+++ b/sys/dev/aic7xxx/aicasm_symbol.h
@@ -13,6 +13,9 @@
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -51,10 +54,10 @@ typedef enum {
}amode_t;
struct reg_info {
- u_int8_t address;
+ uint8_t address;
int size;
amode_t mode;
- u_int8_t valid_bitmask;
+ uint8_t valid_bitmask;
int typecheck_masks;
};
@@ -62,11 +65,11 @@ typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
struct mask_info {
symlist_t symrefs;
- u_int8_t mask;
+ uint8_t mask;
};
struct const_info {
- u_int8_t value;
+ uint8_t value;
int define;
};
OpenPOWER on IntegriCloud