1717d4247SJustin T. Gibbs /* 2717d4247SJustin T. Gibbs * Product specific probe and attach routines for: 3717d4247SJustin T. Gibbs * 27/284X and aic7770 motherboard SCSI controllers 4717d4247SJustin T. Gibbs * 5717d4247SJustin T. Gibbs * Copyright (c) 1994, 1995, 1996, 1997, 1998, 2000 Justin T. Gibbs. 6717d4247SJustin T. Gibbs * All rights reserved. 7717d4247SJustin T. Gibbs * 8717d4247SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 9717d4247SJustin T. Gibbs * modification, are permitted provided that the following conditions 10717d4247SJustin T. Gibbs * are met: 11717d4247SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 12717d4247SJustin T. Gibbs * notice immediately at the beginning of the file, without modification, 13717d4247SJustin T. Gibbs * this list of conditions, and the following disclaimer. 14717d4247SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 15717d4247SJustin T. Gibbs * derived from this software without specific prior written permission. 16717d4247SJustin T. Gibbs * 17717d4247SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18717d4247SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19717d4247SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20717d4247SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21717d4247SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22717d4247SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23717d4247SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24717d4247SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25717d4247SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26717d4247SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27717d4247SJustin T. Gibbs * SUCH DAMAGE. 28717d4247SJustin T. Gibbs * 29717d4247SJustin T. Gibbs * $Id$ 30717d4247SJustin T. Gibbs * 31717d4247SJustin T. Gibbs * $FreeBSD$ 32717d4247SJustin T. Gibbs */ 33717d4247SJustin T. Gibbs 34717d4247SJustin T. Gibbs #ifdef __linux__ 35717d4247SJustin T. Gibbs #include "aic7xxx_linux.h" 36717d4247SJustin T. Gibbs #include "aic7xxx_inline.h" 37717d4247SJustin T. Gibbs #include "aic7xxx_93cx6.h" 38717d4247SJustin T. Gibbs #endif 39717d4247SJustin T. Gibbs 40717d4247SJustin T. Gibbs #ifdef __FreeBSD__ 41717d4247SJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_freebsd.h> 42717d4247SJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_inline.h> 43717d4247SJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_93cx6.h> 44717d4247SJustin T. Gibbs #endif 45717d4247SJustin T. Gibbs 46717d4247SJustin T. Gibbs #define ID_AIC7770 0x04907770 47717d4247SJustin T. Gibbs #define ID_AHA_274x 0x04907771 48717d4247SJustin T. Gibbs #define ID_AHA_284xB 0x04907756 /* BIOS enabled */ 49717d4247SJustin T. Gibbs #define ID_AHA_284x 0x04907757 /* BIOS disabled*/ 50717d4247SJustin T. Gibbs 51717d4247SJustin T. Gibbs static void aha2840_load_seeprom(struct ahc_softc *ahc); 52717d4247SJustin T. Gibbs static ahc_device_setup_t ahc_aic7770_VL_setup; 53717d4247SJustin T. Gibbs static ahc_device_setup_t ahc_aic7770_EISA_setup;; 54717d4247SJustin T. Gibbs static ahc_device_setup_t ahc_aic7770_setup; 55717d4247SJustin T. Gibbs 56717d4247SJustin T. Gibbs 57717d4247SJustin T. Gibbs struct aic7770_identity aic7770_ident_table [] = 58717d4247SJustin T. Gibbs { 59717d4247SJustin T. Gibbs { 60717d4247SJustin T. Gibbs ID_AHA_274x, 61717d4247SJustin T. Gibbs 0xFFFFFFFF, 62717d4247SJustin T. Gibbs "Adaptec 274X SCSI adapter", 63717d4247SJustin T. Gibbs ahc_aic7770_EISA_setup 64717d4247SJustin T. Gibbs }, 65717d4247SJustin T. Gibbs { 66717d4247SJustin T. Gibbs ID_AHA_284xB, 67717d4247SJustin T. Gibbs 0xFFFFFFFE, 68717d4247SJustin T. Gibbs "Adaptec 284X SCSI adapter", 69717d4247SJustin T. Gibbs ahc_aic7770_VL_setup 70717d4247SJustin T. Gibbs }, 71717d4247SJustin T. Gibbs /* Generic chip probes for devices we don't know 'exactly' */ 72717d4247SJustin T. Gibbs { 73717d4247SJustin T. Gibbs ID_AIC7770, 74717d4247SJustin T. Gibbs 0xFFFFFFFF, 75717d4247SJustin T. Gibbs "Adaptec aic7770 SCSI adapter", 76717d4247SJustin T. Gibbs ahc_aic7770_EISA_setup 77717d4247SJustin T. Gibbs } 78717d4247SJustin T. Gibbs }; 79717d4247SJustin T. Gibbs const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table); 80717d4247SJustin T. Gibbs 81717d4247SJustin T. Gibbs struct aic7770_identity * 82717d4247SJustin T. Gibbs aic7770_find_device(uint32_t id) 83717d4247SJustin T. Gibbs { 84717d4247SJustin T. Gibbs struct aic7770_identity *entry; 85717d4247SJustin T. Gibbs int i; 86717d4247SJustin T. Gibbs 87717d4247SJustin T. Gibbs for (i = 0; i < ahc_num_aic7770_devs; i++) { 88717d4247SJustin T. Gibbs entry = &aic7770_ident_table[i]; 89717d4247SJustin T. Gibbs if (entry->full_id == (id & entry->id_mask)) 90717d4247SJustin T. Gibbs return (entry); 91717d4247SJustin T. Gibbs } 92717d4247SJustin T. Gibbs return (NULL); 93717d4247SJustin T. Gibbs } 94717d4247SJustin T. Gibbs 95717d4247SJustin T. Gibbs int 96717d4247SJustin T. Gibbs aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) 97717d4247SJustin T. Gibbs { 98717d4247SJustin T. Gibbs struct ahc_probe_config probe_config; 99717d4247SJustin T. Gibbs int error; 100717d4247SJustin T. Gibbs u_int hostconf; 101717d4247SJustin T. Gibbs 102717d4247SJustin T. Gibbs ahc_init_probe_config(&probe_config); 103717d4247SJustin T. Gibbs error = entry->setup(ahc->dev_softc, &probe_config); 104717d4247SJustin T. Gibbs if (error != 0) 105717d4247SJustin T. Gibbs return (error); 106717d4247SJustin T. Gibbs 107717d4247SJustin T. Gibbs error = aic7770_map_registers(ahc); 108717d4247SJustin T. Gibbs if (error != 0) 109717d4247SJustin T. Gibbs return (error); 110717d4247SJustin T. Gibbs 111717d4247SJustin T. Gibbs probe_config.description = entry->name; 112717d4247SJustin T. Gibbs error = ahc_softc_init(ahc, &probe_config); 113717d4247SJustin T. Gibbs 114717d4247SJustin T. Gibbs error = aic7770_map_int(ahc); 115717d4247SJustin T. Gibbs if (error != 0) 116717d4247SJustin T. Gibbs return (error); 117717d4247SJustin T. Gibbs 118717d4247SJustin T. Gibbs error = ahc_reset(ahc); 119717d4247SJustin T. Gibbs if (error != 0) 120717d4247SJustin T. Gibbs return (error); 121717d4247SJustin T. Gibbs 122717d4247SJustin T. Gibbs switch (probe_config.chip & (AHC_EISA|AHC_VL)) { 123717d4247SJustin T. Gibbs case AHC_EISA: 124717d4247SJustin T. Gibbs { 125717d4247SJustin T. Gibbs u_int biosctrl; 126717d4247SJustin T. Gibbs u_int scsiconf; 127717d4247SJustin T. Gibbs u_int scsiconf1; 128717d4247SJustin T. Gibbs 129717d4247SJustin T. Gibbs biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); 130717d4247SJustin T. Gibbs scsiconf = ahc_inb(ahc, SCSICONF); 131717d4247SJustin T. Gibbs scsiconf1 = ahc_inb(ahc, SCSICONF + 1); 132717d4247SJustin T. Gibbs 133717d4247SJustin T. Gibbs /* Get the primary channel information */ 134717d4247SJustin T. Gibbs if ((biosctrl & CHANNEL_B_PRIMARY) != 0) 135717d4247SJustin T. Gibbs ahc->flags |= AHC_CHANNEL_B_PRIMARY; 136717d4247SJustin T. Gibbs 137717d4247SJustin T. Gibbs if ((biosctrl & BIOSMODE) == BIOSDISABLED) { 138717d4247SJustin T. Gibbs ahc->flags |= AHC_USEDEFAULTS; 139717d4247SJustin T. Gibbs } else { 140717d4247SJustin T. Gibbs if ((ahc->features & AHC_WIDE) != 0) { 141717d4247SJustin T. Gibbs ahc->our_id = scsiconf1 & HWSCSIID; 142717d4247SJustin T. Gibbs if (scsiconf & TERM_ENB) 143717d4247SJustin T. Gibbs ahc->flags |= AHC_TERM_ENB_A; 144717d4247SJustin T. Gibbs } else { 145717d4247SJustin T. Gibbs ahc->our_id = scsiconf & HSCSIID; 146717d4247SJustin T. Gibbs ahc->our_id_b = scsiconf1 & HSCSIID; 147717d4247SJustin T. Gibbs if (scsiconf & TERM_ENB) 148717d4247SJustin T. Gibbs ahc->flags |= AHC_TERM_ENB_A; 149717d4247SJustin T. Gibbs if (scsiconf1 & TERM_ENB) 150717d4247SJustin T. Gibbs ahc->flags |= AHC_TERM_ENB_B; 151717d4247SJustin T. Gibbs } 152717d4247SJustin T. Gibbs } 153717d4247SJustin T. Gibbs /* 154717d4247SJustin T. Gibbs * We have no way to tell, so assume extended 155717d4247SJustin T. Gibbs * translation is enabled. 156717d4247SJustin T. Gibbs */ 157717d4247SJustin T. Gibbs ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; 158717d4247SJustin T. Gibbs break; 159717d4247SJustin T. Gibbs } 160717d4247SJustin T. Gibbs case AHC_VL: 161717d4247SJustin T. Gibbs { 162717d4247SJustin T. Gibbs aha2840_load_seeprom(ahc); 163717d4247SJustin T. Gibbs break; 164717d4247SJustin T. Gibbs } 165717d4247SJustin T. Gibbs default: 166717d4247SJustin T. Gibbs break; 167717d4247SJustin T. Gibbs } 168717d4247SJustin T. Gibbs 169717d4247SJustin T. Gibbs /* 170717d4247SJustin T. Gibbs * Ensure autoflush is enabled 171717d4247SJustin T. Gibbs */ 172717d4247SJustin T. Gibbs ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); 173717d4247SJustin T. Gibbs 174717d4247SJustin T. Gibbs /* Setup the FIFO threshold and the bus off time */ 175717d4247SJustin T. Gibbs hostconf = ahc_inb(ahc, HOSTCONF); 176717d4247SJustin T. Gibbs ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); 177717d4247SJustin T. Gibbs ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); 178717d4247SJustin T. Gibbs 179717d4247SJustin T. Gibbs /* 180717d4247SJustin T. Gibbs * Generic aic7xxx initialization. 181717d4247SJustin T. Gibbs */ 182717d4247SJustin T. Gibbs error = ahc_init(ahc); 183717d4247SJustin T. Gibbs if (error != 0) 184717d4247SJustin T. Gibbs return (error); 185717d4247SJustin T. Gibbs 186717d4247SJustin T. Gibbs /* 187717d4247SJustin T. Gibbs * Enable the board's BUS drivers 188717d4247SJustin T. Gibbs */ 189717d4247SJustin T. Gibbs ahc_outb(ahc, BCTL, ENABLE); 190717d4247SJustin T. Gibbs 191717d4247SJustin T. Gibbs return (0); 192717d4247SJustin T. Gibbs } 193717d4247SJustin T. Gibbs 194717d4247SJustin T. Gibbs /* 195717d4247SJustin T. Gibbs * Read the 284x SEEPROM. 196717d4247SJustin T. Gibbs */ 197717d4247SJustin T. Gibbs static void 198717d4247SJustin T. Gibbs aha2840_load_seeprom(struct ahc_softc *ahc) 199717d4247SJustin T. Gibbs { 200717d4247SJustin T. Gibbs struct seeprom_descriptor sd; 201717d4247SJustin T. Gibbs struct seeprom_config sc; 202717d4247SJustin T. Gibbs uint16_t checksum = 0; 203717d4247SJustin T. Gibbs uint8_t scsi_conf; 204717d4247SJustin T. Gibbs int have_seeprom; 205717d4247SJustin T. Gibbs 206717d4247SJustin T. Gibbs sd.sd_ahc = ahc; 207717d4247SJustin T. Gibbs sd.sd_control_offset = SEECTL_2840; 208717d4247SJustin T. Gibbs sd.sd_status_offset = STATUS_2840; 209717d4247SJustin T. Gibbs sd.sd_dataout_offset = STATUS_2840; 210717d4247SJustin T. Gibbs sd.sd_chip = C46; 211717d4247SJustin T. Gibbs sd.sd_MS = 0; 212717d4247SJustin T. Gibbs sd.sd_RDY = EEPROM_TF; 213717d4247SJustin T. Gibbs sd.sd_CS = CS_2840; 214717d4247SJustin T. Gibbs sd.sd_CK = CK_2840; 215717d4247SJustin T. Gibbs sd.sd_DO = DO_2840; 216717d4247SJustin T. Gibbs sd.sd_DI = DI_2840; 217717d4247SJustin T. Gibbs 218717d4247SJustin T. Gibbs if (bootverbose) 219717d4247SJustin T. Gibbs printf("%s: Reading SEEPROM...", ahc_name(ahc)); 220717d4247SJustin T. Gibbs have_seeprom = read_seeprom(&sd, 221717d4247SJustin T. Gibbs (uint16_t *)&sc, 222717d4247SJustin T. Gibbs /*start_addr*/0, 223717d4247SJustin T. Gibbs sizeof(sc)/2); 224717d4247SJustin T. Gibbs 225717d4247SJustin T. Gibbs if (have_seeprom) { 226717d4247SJustin T. Gibbs /* Check checksum */ 227717d4247SJustin T. Gibbs int i; 228717d4247SJustin T. Gibbs int maxaddr = (sizeof(sc)/2) - 1; 229717d4247SJustin T. Gibbs uint16_t *scarray = (uint16_t *)≻ 230717d4247SJustin T. Gibbs 231717d4247SJustin T. Gibbs for (i = 0; i < maxaddr; i++) 232717d4247SJustin T. Gibbs checksum = checksum + scarray[i]; 233717d4247SJustin T. Gibbs if (checksum != sc.checksum) { 234717d4247SJustin T. Gibbs if(bootverbose) 235717d4247SJustin T. Gibbs printf ("checksum error\n"); 236717d4247SJustin T. Gibbs have_seeprom = 0; 237717d4247SJustin T. Gibbs } else if (bootverbose) { 238717d4247SJustin T. Gibbs printf("done.\n"); 239717d4247SJustin T. Gibbs } 240717d4247SJustin T. Gibbs } 241717d4247SJustin T. Gibbs 242717d4247SJustin T. Gibbs if (!have_seeprom) { 243717d4247SJustin T. Gibbs if (bootverbose) 244717d4247SJustin T. Gibbs printf("%s: No SEEPROM available\n", ahc_name(ahc)); 245717d4247SJustin T. Gibbs ahc->flags |= AHC_USEDEFAULTS; 246717d4247SJustin T. Gibbs } else { 247717d4247SJustin T. Gibbs /* 248717d4247SJustin T. Gibbs * Put the data we've collected down into SRAM 249717d4247SJustin T. Gibbs * where ahc_init will find it. 250717d4247SJustin T. Gibbs */ 251717d4247SJustin T. Gibbs int i; 252717d4247SJustin T. Gibbs int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; 253717d4247SJustin T. Gibbs uint16_t discenable; 254717d4247SJustin T. Gibbs 255717d4247SJustin T. Gibbs discenable = 0; 256717d4247SJustin T. Gibbs for (i = 0; i < max_targ; i++){ 257717d4247SJustin T. Gibbs uint8_t target_settings; 258717d4247SJustin T. Gibbs target_settings = (sc.device_flags[i] & CFXFER) << 4; 259717d4247SJustin T. Gibbs if (sc.device_flags[i] & CFSYNCH) 260717d4247SJustin T. Gibbs target_settings |= SOFS; 261717d4247SJustin T. Gibbs if (sc.device_flags[i] & CFWIDEB) 262717d4247SJustin T. Gibbs target_settings |= WIDEXFER; 263717d4247SJustin T. Gibbs if (sc.device_flags[i] & CFDISC) 264717d4247SJustin T. Gibbs discenable |= (0x01 << i); 265717d4247SJustin T. Gibbs ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); 266717d4247SJustin T. Gibbs } 267717d4247SJustin T. Gibbs ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); 268717d4247SJustin T. Gibbs ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); 269717d4247SJustin T. Gibbs 270717d4247SJustin T. Gibbs ahc->our_id = sc.brtime_id & CFSCSIID; 271717d4247SJustin T. Gibbs 272717d4247SJustin T. Gibbs scsi_conf = (ahc->our_id & 0x7); 273717d4247SJustin T. Gibbs if (sc.adapter_control & CFSPARITY) 274717d4247SJustin T. Gibbs scsi_conf |= ENSPCHK; 275717d4247SJustin T. Gibbs if (sc.adapter_control & CFRESETB) 276717d4247SJustin T. Gibbs scsi_conf |= RESET_SCSI; 277717d4247SJustin T. Gibbs 278717d4247SJustin T. Gibbs if (sc.bios_control & CF284XEXTEND) 279717d4247SJustin T. Gibbs ahc->flags |= AHC_EXTENDED_TRANS_A; 280717d4247SJustin T. Gibbs /* Set SCSICONF info */ 281717d4247SJustin T. Gibbs ahc_outb(ahc, SCSICONF, scsi_conf); 282717d4247SJustin T. Gibbs 283717d4247SJustin T. Gibbs if (sc.adapter_control & CF284XSTERM) 284717d4247SJustin T. Gibbs ahc->flags |= AHC_TERM_ENB_A; 285717d4247SJustin T. Gibbs } 286717d4247SJustin T. Gibbs } 287717d4247SJustin T. Gibbs 288717d4247SJustin T. Gibbs static int 289717d4247SJustin T. Gibbs ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) 290717d4247SJustin T. Gibbs { 291717d4247SJustin T. Gibbs int error; 292717d4247SJustin T. Gibbs 293717d4247SJustin T. Gibbs error = ahc_aic7770_setup(dev, probe_config); 294717d4247SJustin T. Gibbs probe_config->chip |= AHC_VL; 295717d4247SJustin T. Gibbs return (error); 296717d4247SJustin T. Gibbs } 297717d4247SJustin T. Gibbs 298717d4247SJustin T. Gibbs static int 299717d4247SJustin T. Gibbs ahc_aic7770_EISA_setup(ahc_dev_softc_t dev, 300717d4247SJustin T. Gibbs struct ahc_probe_config *probe_config) 301717d4247SJustin T. Gibbs { 302717d4247SJustin T. Gibbs int error; 303717d4247SJustin T. Gibbs 304717d4247SJustin T. Gibbs error = ahc_aic7770_setup(dev, probe_config); 305717d4247SJustin T. Gibbs probe_config->chip |= AHC_EISA; 306717d4247SJustin T. Gibbs return (error); 307717d4247SJustin T. Gibbs } 308717d4247SJustin T. Gibbs 309717d4247SJustin T. Gibbs static int 310717d4247SJustin T. Gibbs ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) 311717d4247SJustin T. Gibbs { 312717d4247SJustin T. Gibbs probe_config->channel = 'A'; 313717d4247SJustin T. Gibbs probe_config->channel_b = 'B'; 314717d4247SJustin T. Gibbs probe_config->chip = AHC_AIC7770; 315717d4247SJustin T. Gibbs probe_config->features = AHC_AIC7770_FE; 316717d4247SJustin T. Gibbs probe_config->bugs |= AHC_TMODE_WIDEODD_BUG; 317717d4247SJustin T. Gibbs probe_config->flags |= AHC_PAGESCBS; 318717d4247SJustin T. Gibbs return (0); 319717d4247SJustin T. Gibbs } 320