1 /* 2 * Product specific probe and attach routines for: 3 * 27/284X and aic7770 motherboard SCSI controllers 4 * 5 * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice immediately at the beginning of the file, without modification, 13 * this list of conditions, and the following disclaimer. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * Alternatively, this software may be distributed under the terms of the 18 * GNU Public License ("GPL"). 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: //depot/src/aic7xxx/aic7770.c#11 $ 33 * 34 * $FreeBSD$ 35 */ 36 37 #include <dev/aic7xxx/aic7xxx_freebsd.h> 38 #include <dev/aic7xxx/aic7xxx_inline.h> 39 #include <dev/aic7xxx/aic7xxx_93cx6.h> 40 41 #define ID_AIC7770 0x04907770 42 #define ID_AHA_274x 0x04907771 43 #define ID_AHA_284xB 0x04907756 /* BIOS enabled */ 44 #define ID_AHA_284x 0x04907757 /* BIOS disabled*/ 45 46 static void aha2840_load_seeprom(struct ahc_softc *ahc); 47 static ahc_device_setup_t ahc_aic7770_VL_setup; 48 static ahc_device_setup_t ahc_aic7770_EISA_setup;; 49 static ahc_device_setup_t ahc_aic7770_setup; 50 51 52 struct aic7770_identity aic7770_ident_table [] = 53 { 54 { 55 ID_AHA_274x, 56 0xFFFFFFFF, 57 "Adaptec 274X SCSI adapter", 58 ahc_aic7770_EISA_setup 59 }, 60 { 61 ID_AHA_284xB, 62 0xFFFFFFFE, 63 "Adaptec 284X SCSI adapter", 64 ahc_aic7770_VL_setup 65 }, 66 /* Generic chip probes for devices we don't know 'exactly' */ 67 { 68 ID_AIC7770, 69 0xFFFFFFFF, 70 "Adaptec aic7770 SCSI adapter", 71 ahc_aic7770_EISA_setup 72 } 73 }; 74 const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table); 75 76 struct aic7770_identity * 77 aic7770_find_device(uint32_t id) 78 { 79 struct aic7770_identity *entry; 80 int i; 81 82 for (i = 0; i < ahc_num_aic7770_devs; i++) { 83 entry = &aic7770_ident_table[i]; 84 if (entry->full_id == (id & entry->id_mask)) 85 return (entry); 86 } 87 return (NULL); 88 } 89 90 int 91 aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) 92 { 93 struct ahc_probe_config probe_config; 94 int error; 95 u_int hostconf; 96 u_int irq; 97 u_int intdef; 98 99 ahc_init_probe_config(&probe_config); 100 error = entry->setup(ahc->dev_softc, &probe_config); 101 if (error != 0) 102 return (error); 103 104 error = aic7770_map_registers(ahc); 105 if (error != 0) 106 return (error); 107 108 probe_config.description = entry->name; 109 error = ahc_softc_init(ahc, &probe_config); 110 111 error = ahc_reset(ahc); 112 if (error != 0) 113 return (error); 114 115 /* Make sure we have a valid interrupt vector */ 116 intdef = ahc_inb(ahc, INTDEF); 117 irq = intdef & VECTOR; 118 switch (irq) { 119 case 9: 120 case 10: 121 case 11: 122 case 12: 123 case 14: 124 case 15: 125 break; 126 default: 127 printf("aic7770_config: illegal irq setting %d\n", intdef); 128 return (ENXIO); 129 } 130 131 if ((intdef & EDGE_TRIG) != 0) 132 ahc->flags |= AHC_EDGE_INTERRUPT; 133 134 switch (probe_config.chip & (AHC_EISA|AHC_VL)) { 135 case AHC_EISA: 136 { 137 u_int biosctrl; 138 u_int scsiconf; 139 u_int scsiconf1; 140 141 biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); 142 scsiconf = ahc_inb(ahc, SCSICONF); 143 scsiconf1 = ahc_inb(ahc, SCSICONF + 1); 144 145 /* Get the primary channel information */ 146 if ((biosctrl & CHANNEL_B_PRIMARY) != 0) 147 ahc->flags |= 1; 148 149 if ((biosctrl & BIOSMODE) == BIOSDISABLED) { 150 ahc->flags |= AHC_USEDEFAULTS; 151 } else { 152 if ((ahc->features & AHC_WIDE) != 0) { 153 ahc->our_id = scsiconf1 & HWSCSIID; 154 if (scsiconf & TERM_ENB) 155 ahc->flags |= AHC_TERM_ENB_A; 156 } else { 157 ahc->our_id = scsiconf & HSCSIID; 158 ahc->our_id_b = scsiconf1 & HSCSIID; 159 if (scsiconf & TERM_ENB) 160 ahc->flags |= AHC_TERM_ENB_A; 161 if (scsiconf1 & TERM_ENB) 162 ahc->flags |= AHC_TERM_ENB_B; 163 } 164 } 165 /* 166 * We have no way to tell, so assume extended 167 * translation is enabled. 168 */ 169 ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; 170 break; 171 } 172 case AHC_VL: 173 { 174 aha2840_load_seeprom(ahc); 175 break; 176 } 177 default: 178 break; 179 } 180 181 /* 182 * Ensure autoflush is enabled 183 */ 184 ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); 185 186 /* Setup the FIFO threshold and the bus off time */ 187 hostconf = ahc_inb(ahc, HOSTCONF); 188 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); 189 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); 190 191 /* 192 * Generic aic7xxx initialization. 193 */ 194 error = ahc_init(ahc); 195 if (error != 0) 196 return (error); 197 198 /* 199 * Link this softc in with all other ahc instances. 200 */ 201 ahc_softc_insert(ahc); 202 203 error = aic7770_map_int(ahc, irq); 204 if (error != 0) 205 return (error); 206 207 /* 208 * Enable the board's BUS drivers 209 */ 210 ahc_outb(ahc, BCTL, ENABLE); 211 212 /* 213 * Allow interrupts. 214 */ 215 ahc_intr_enable(ahc, TRUE); 216 217 return (0); 218 } 219 220 /* 221 * Read the 284x SEEPROM. 222 */ 223 static void 224 aha2840_load_seeprom(struct ahc_softc *ahc) 225 { 226 struct seeprom_descriptor sd; 227 struct seeprom_config sc; 228 uint16_t checksum = 0; 229 uint8_t scsi_conf; 230 int have_seeprom; 231 232 sd.sd_ahc = ahc; 233 sd.sd_control_offset = SEECTL_2840; 234 sd.sd_status_offset = STATUS_2840; 235 sd.sd_dataout_offset = STATUS_2840; 236 sd.sd_chip = C46; 237 sd.sd_MS = 0; 238 sd.sd_RDY = EEPROM_TF; 239 sd.sd_CS = CS_2840; 240 sd.sd_CK = CK_2840; 241 sd.sd_DO = DO_2840; 242 sd.sd_DI = DI_2840; 243 244 if (bootverbose) 245 printf("%s: Reading SEEPROM...", ahc_name(ahc)); 246 have_seeprom = read_seeprom(&sd, 247 (uint16_t *)&sc, 248 /*start_addr*/0, 249 sizeof(sc)/2); 250 251 if (have_seeprom) { 252 /* Check checksum */ 253 int i; 254 int maxaddr = (sizeof(sc)/2) - 1; 255 uint16_t *scarray = (uint16_t *)≻ 256 257 for (i = 0; i < maxaddr; i++) 258 checksum = checksum + scarray[i]; 259 if (checksum != sc.checksum) { 260 if(bootverbose) 261 printf ("checksum error\n"); 262 have_seeprom = 0; 263 } else if (bootverbose) { 264 printf("done.\n"); 265 } 266 } 267 268 if (!have_seeprom) { 269 if (bootverbose) 270 printf("%s: No SEEPROM available\n", ahc_name(ahc)); 271 ahc->flags |= AHC_USEDEFAULTS; 272 } else { 273 /* 274 * Put the data we've collected down into SRAM 275 * where ahc_init will find it. 276 */ 277 int i; 278 int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; 279 uint16_t discenable; 280 281 discenable = 0; 282 for (i = 0; i < max_targ; i++){ 283 uint8_t target_settings; 284 target_settings = (sc.device_flags[i] & CFXFER) << 4; 285 if (sc.device_flags[i] & CFSYNCH) 286 target_settings |= SOFS; 287 if (sc.device_flags[i] & CFWIDEB) 288 target_settings |= WIDEXFER; 289 if (sc.device_flags[i] & CFDISC) 290 discenable |= (0x01 << i); 291 ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); 292 } 293 ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); 294 ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); 295 296 ahc->our_id = sc.brtime_id & CFSCSIID; 297 298 scsi_conf = (ahc->our_id & 0x7); 299 if (sc.adapter_control & CFSPARITY) 300 scsi_conf |= ENSPCHK; 301 if (sc.adapter_control & CFRESETB) 302 scsi_conf |= RESET_SCSI; 303 304 if (sc.bios_control & CF284XEXTEND) 305 ahc->flags |= AHC_EXTENDED_TRANS_A; 306 /* Set SCSICONF info */ 307 ahc_outb(ahc, SCSICONF, scsi_conf); 308 309 if (sc.adapter_control & CF284XSTERM) 310 ahc->flags |= AHC_TERM_ENB_A; 311 } 312 } 313 314 static int 315 ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) 316 { 317 int error; 318 319 error = ahc_aic7770_setup(dev, probe_config); 320 probe_config->chip |= AHC_VL; 321 return (error); 322 } 323 324 static int 325 ahc_aic7770_EISA_setup(ahc_dev_softc_t dev, 326 struct ahc_probe_config *probe_config) 327 { 328 int error; 329 330 error = ahc_aic7770_setup(dev, probe_config); 331 probe_config->chip |= AHC_EISA; 332 return (error); 333 } 334 335 static int 336 ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) 337 { 338 probe_config->channel = 'A'; 339 probe_config->channel_b = 'B'; 340 probe_config->chip = AHC_AIC7770; 341 probe_config->features = AHC_AIC7770_FE; 342 probe_config->bugs |= AHC_TMODE_WIDEODD_BUG; 343 probe_config->flags |= AHC_PAGESCBS; 344 return (0); 345 } 346