summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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