diff --git a/sys/dev/aic7xxx/93cx6.c b/sys/dev/aic7xxx/93cx6.c index 06e547b57b13..62a4aeefa9c1 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 7875032e28de..8fd7bb9be1ed 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 4e91eed4974b..1e0e16ad8a7c 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 *)≻ + uint16_t *scarray = (uint16_t *)≻ 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 d457f6c2dc28..4a22f3aec19f 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; + 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; + } + + ahc_outb(ahc, DSCOMMAND0, dscommand0); + + /* See if we have a SEEPROM and perform auto-term */ + check_extport(ahc, &sxfrctl1); + /* - * Do aic7880/aic7870/aic7860/aic7850 specific initialization + * Take the LED out of diagnostic mode */ - { - u_int8_t sblkctl; - u_int dscommand0; + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); - 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 &= ~(USCBSIZE32|DPARCKEN); - dscommand0 |= CACHETHEN; - } - - ahc_outb(ahc, DSCOMMAND0, dscommand0); - - /* See if we have an SEEPROM and perform auto-term */ - check_extport(ahc, &sxfrctl1); + /* + * 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) { /* - * Take the LED out of diagnostic mode + * PCI Adapter default setup + * Should only be used if the adapter does not have + * an SEEPROM. */ - 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); + /* 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,40 +1109,51 @@ 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; + if (have_seeprom) + have_seeprom = verify_cksum(&sc); - maxaddr = (sizeof(sc)/2) - 1; - checksum = 0; - scarray = (u_int16_t *)≻ - - 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 != 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 *)≻ + 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)); @@ -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) -{ - *channel = 'A'; - *chip = AHC_AIC7880; - *features = AHC_AIC7880_FE; - return (0); -} - -static int -ahc_2940Pro_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) { int error; - *flags |= AHC_INT50_SPEEDFLEX; - error = ahc_aic7880_setup(dev, channel, chip, features, flags); - return (0); -} - -static int -ahc_aha394XU_setup(device_t dev, char *channel, ahc_chip *chip, - ahc_feature *features, ahc_flag *flags) -{ - int error; - - error = ahc_aic7880_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_aha494XX_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_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, struct ahc_probe_config *probe_config) { int error; - 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, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7880_setup(dev, probe_config); if (error == 0) - error = ahc_aha398XX_setup(dev, channel, chip, features, flags); + error = ahc_aha394XX_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_aha398XU_setup(device_t dev, struct ahc_probe_config *probe_config) { - *channel = 'A'; - *chip = AHC_AIC7890; - *features = AHC_AIC7890_FE; - *flags |= AHC_NEWEEPROM_FMT; + int error; + + error = ahc_aic7880_setup(dev, probe_config); + if (error == 0) + error = ahc_aha398XX_setup(dev, probe_config); + return (error); +} + +static int +ahc_aic7890_setup(device_t dev, struct ahc_probe_config *probe_config) +{ + 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)); - *channel = 'A'; + probe_config->channel = 'A'; + break; } - *flags |= AHC_LARGE_SEEPROM; + 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)); + probe_config->channel = 'A'; + } + probe_config->flags |= AHC_LARGE_SEEPROM; return (0); } diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index e89434ae2e00..3859c190042c 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 #include #include +#include #include #include @@ -117,7 +118,7 @@ #include #include -#include +#include #include #include @@ -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; + struct ahc_dma_seg *sg; + uint32_t data_cnt; + uint32_t data_addr; - data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16) - | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8) - | (ahc_inb(ahc, SCB_RESID_DCNT)); + /* 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,34 +4493,12 @@ 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->init_level++; - - /* Allocate SCB data now that buffer_dmat is initialized */ - if (ahc->scb_data->maxhscbs == 0) - 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; - - /* All of our queues are empty */ - for (i = 0; i < 256; i++) - ahc->qoutfifo[i] = SCB_LIST_NULL; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - ahc_outb(ahc, TARGID, 0); - ahc_outb(ahc, TARGID + 1, 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->untagged_scbs[256]; + 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. */ @@ -4190,6 +4507,32 @@ ahc_init(struct ahc_softc *ahc) 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++; + + /* Allocate SCB data now that buffer_dmat is initialized */ + if (ahc->scb_data->maxhscbs == 0) + if (ahcinitscbdata(ahc) != 0) + return (ENOMEM); + + /* There are no untagged SCBs active yet. */ + /* 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); } /* @@ -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; - - 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)) { - - next = ahc_abort_wscb(ahc, next, prev); - } else { - - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } + i = 0; + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + i = target; + maxtarget = target + 1; } + + for (;i < maxtarget; i++) { + u_int scbid; + + /* 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)); @@ -6531,65 +7018,94 @@ ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width) ahc->msgout_len += 4; } +static void +ahc_construct_ppr(struct ahc_softc *ahc, u_int period, u_int offset, + u_int bus_width, u_int ppr_options) +{ + 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; +} + static void ahc_calc_residual(struct scb *scb) { - struct hardware_scb *hscb; - - hscb = scb->hscb; + 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; - } - -#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 + scb->ccb->csio.sense_resid = resid; } - /* - * Clean out the residual information in this SCB for its - * next consumer. - */ - hscb->residual_SG_count = 0; +#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 } 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 3ef8ef882f67..e491e22ca0b3 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 /* For device_t */ @@ -48,21 +49,38 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #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,25 +153,41 @@ 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 */ @@ -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; @@ -473,6 +605,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. @@ -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,20 +745,6 @@ struct full_ahc_softc { extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */ #endif -char *ahc_name(struct ahc_softc *ahc); - -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 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); - #define ahc_inb(ahc, port) \ bus_space_read_1((ahc)->tag, (ahc)->bsh, port) @@ -627,4 +757,64 @@ void ahc_intr(void *arg); #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, + 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); +} + +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) + ; + + 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 78c95a85a117..d76f44cbdbf4 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 { @@ -1360,14 +1359,6 @@ scratch_ram { size 1 } - /* - * 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 @@ -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 187b22eae925..d2df34ddc299 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->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]; - } - 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 SCSIID_ULTRA2, SCB_SCSIID; + } else if ((ahc->features & AHC_TWIN) != 0) { + and SCSIID, TWIN_TID|OID, SCB_SCSIID; } else { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID, OID; /* Clear old target */ - or SCSIID, A; + mov SCSIID, SCB_SCSIID; + } + if ((ahc->flags & AHC_TARGETMODE) != 0) { + mov SINDEX, SCSISEQ_TEMPLATE; + test SCB_CONTROL, TARGET_SCB jz . + 2; + or SINDEX, TEMODE; + mov SCSISEQ, SINDEX ret; + } else { + 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; - } else { - mov DFDAT, SAVED_TCL; - } - + and SAVED_SCSIID, SELID_MASK, SELID; /* 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; - } + if ((ahc->features & AHC_MULTI_TID) != 0) { + and A, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and A, OID, SCSIID_ULTRA2; } 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; - } + and A, OID, SCSIID; + } + or SAVED_SCSIID, A; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_SCSIID, TWIN_CHNLB; + } + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SAVED_SCSIID; + } else { + 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) { - /* - * Do we have any prefetch left??? - */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; - - /* - * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. - */ - 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; - - /* - * 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 - * }; - */ - mvi HADDR call dfdat_in_7; - } - - /* Track odd'ness */ - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; - - if ((ahc->features & AHC_ULTRA2) == 0) { - /* Load STCNT as well. It is a mirror of HCNT */ +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: + /* + * 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 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. + */ +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 drain + * the prefetched but unused data from the data fifo until + * there is space for the input latch to drain. + */ + mov NONE, DFDAT; + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; + + /* 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; + + /* + * 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; } + + /* 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; + } } - -/* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ - add SG_NEXT[0],SG_SIZEOF; - adc SG_NEXT[1],A; - - if ((ahc->flags & AHC_TARGETMODE) != 0) { - test SSTAT0, TARGET jnz data_phase_loop; - } - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; - - /* 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 */ - } - data_phase_finish: - if ((ahc->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; + /* + * 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_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->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 .; + } + + /* + * 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_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); - } else { - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); } -cmd_loop: + 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, (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; + } +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; @@ -1296,40 +1404,56 @@ 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 */ - } else { - and A,0x07; /* lun in lower three bits */ - } - 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; - } + and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; /* - * 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. + * 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. */ - call rem_scb_from_disc_list; - jmp setup_SCB; + 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 { + mov SCBPTR, A; + } + 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; + } + /* * 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 06e547b57b13..62a4aeefa9c1 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 7875032e28de..8fd7bb9be1ed 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 9af5c8343274..374e86c79ca2 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 7e6b4683dfdb..9faecd0f4f02 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 9af5c8343274..374e86c79ca2 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 7e6b4683dfdb..9faecd0f4f02 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 4d090598e4fa..5731f674bcdf 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 T_STC T_CLC -%token T_CMP T_XOR +%token T_CMP T_NOT T_XOR %token 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); } @@ -850,6 +868,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 ';' { @@ -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 similarity index 78% rename from sys/dev/aic7xxx/sequencer.h rename to sys/dev/aic7xxx/aicasm/aicasm_insformat.h index 4f054916ebe8..64667472b0ae 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 + 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 28689cbd4996..48170d68154d 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 8c250d2317ec..43440ea4f40f 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 79809db8e6a5..37f5e7f66664 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 4d090598e4fa..5731f674bcdf 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 T_STC T_CLC -%token T_CMP T_XOR +%token T_CMP T_NOT T_XOR %token 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); } @@ -850,6 +868,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 ';' { @@ -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 000000000000..64667472b0ae --- /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 + +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 28689cbd4996..48170d68154d 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 8c250d2317ec..43440ea4f40f 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 79809db8e6a5..37f5e7f66664 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; };