ahc_eisa.c revision 41817
1/* 2 * Product specific probe and attach routines for: 3 * 27/284X and aic7770 motherboard SCSI controllers 4 * 5 * Copyright (c) 1994, 1995, 1996, 1997, 1998 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 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: ahc_eisa.c,v 1.3 1998/10/15 18:21:50 gibbs Exp $ 30 */ 31 32#include "eisa.h" 33#if NEISA > 0 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38 39#include <machine/bus_pio.h> 40#include <machine/bus.h> 41 42#include <i386/eisa/eisaconf.h> 43 44#include <cam/cam.h> 45#include <cam/cam_ccb.h> 46#include <cam/cam_sim.h> 47#include <cam/cam_xpt_sim.h> 48#include <cam/scsi/scsi_all.h> 49 50#include <dev/aic7xxx/aic7xxx.h> 51#include <dev/aic7xxx/93cx6.h> 52 53#include <aic7xxx_reg.h> 54 55#define EISA_DEVICE_ID_ADAPTEC_AIC7770 0x04907770 56#define EISA_DEVICE_ID_ADAPTEC_274x 0x04907771 57#define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */ 58#define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/ 59 60#define AHC_EISA_SLOT_OFFSET 0xc00 61#define AHC_EISA_IOSIZE 0x100 62#define INTDEF 0x5cul /* Interrupt Definition Register */ 63 64static int aic7770probe(void); 65static int aic7770_attach(struct eisa_device *e_dev); 66static void aha2840_load_seeprom(struct ahc_softc *ahc); 67 68static struct eisa_driver ahc_eisa_driver = 69{ 70 "ahc", 71 aic7770probe, 72 aic7770_attach, 73 /*shutdown*/NULL, 74 &ahc_unit 75}; 76 77DATA_SET (eisadriver_set, ahc_eisa_driver); 78 79static const char *aic7770_match(eisa_id_t type); 80 81static const char* 82aic7770_match(type) 83 eisa_id_t type; 84{ 85 switch (type) { 86 case EISA_DEVICE_ID_ADAPTEC_AIC7770: 87 return ("Adaptec aic7770 SCSI host adapter"); 88 break; 89 case EISA_DEVICE_ID_ADAPTEC_274x: 90 return ("Adaptec 274X SCSI host adapter"); 91 break; 92 case EISA_DEVICE_ID_ADAPTEC_284xB: 93 case EISA_DEVICE_ID_ADAPTEC_284x: 94 return ("Adaptec 284X SCSI host adapter"); 95 break; 96 default: 97 break; 98 } 99 return (NULL); 100} 101 102static int 103aic7770probe(void) 104{ 105 u_int32_t iobase; 106 u_int32_t irq; 107 u_int8_t intdef; 108 u_int8_t hcntrl; 109 struct eisa_device *e_dev; 110 int count; 111 112 e_dev = NULL; 113 count = 0; 114 while ((e_dev = eisa_match_dev(e_dev, aic7770_match))) { 115 iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) 116 + AHC_EISA_SLOT_OFFSET; 117 118 /* Pause the card preseving the IRQ type */ 119 hcntrl = inb(iobase + HCNTRL) & IRQMS; 120 121 outb(iobase + HCNTRL, hcntrl | PAUSE); 122 123 eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE); 124 intdef = inb(INTDEF + iobase); 125 irq = intdef & 0xf; 126 switch (irq) { 127 case 9: 128 case 10: 129 case 11: 130 case 12: 131 case 14: 132 case 15: 133 break; 134 default: 135 printf("aic7770 at slot %d: illegal " 136 "irq setting %d\n", e_dev->ioconf.slot, 137 intdef); 138 irq = 0; 139 break; 140 } 141 if (irq == 0) 142 continue; 143 eisa_add_intr(e_dev, irq); 144 eisa_registerdev(e_dev, &ahc_eisa_driver); 145 count++; 146 } 147 return count; 148} 149 150static int 151aic7770_attach(struct eisa_device *e_dev) 152{ 153 ahc_chip chip; 154 155 struct ahc_softc *ahc; 156 resvaddr_t *iospace; 157 int unit = e_dev->unit; 158 int irq; 159 int error; 160 161 if (TAILQ_FIRST(&e_dev->ioconf.irqs) == NULL) 162 return (-1); 163 164 irq = TAILQ_FIRST(&e_dev->ioconf.irqs)->irq_no; 165 166 iospace = e_dev->ioconf.ioaddrs.lh_first; 167 168 if (!iospace) 169 return -1; 170 171 switch (e_dev->id) { 172 case EISA_DEVICE_ID_ADAPTEC_274x: 173 case EISA_DEVICE_ID_ADAPTEC_AIC7770: 174 chip = AHC_AIC7770|AHC_EISA; 175 break; 176 case EISA_DEVICE_ID_ADAPTEC_284xB: 177 case EISA_DEVICE_ID_ADAPTEC_284x: 178 chip = AHC_AIC7770|AHC_VL; 179 break; 180 default: 181 printf("aic7770_attach: Unknown device type!\n"); 182 return -1; 183 break; 184 } 185 186 if (!(ahc = ahc_alloc(unit, iospace->addr, NULL, 187 chip, AHC_AIC7770_FE, AHC_FNONE, NULL))) 188 return -1; 189 190 ahc->channel = 'A'; 191 ahc->channel_b = 'B'; 192 /* XXX Should be a child of the EISA bus dma tag */ 193 error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0, 194 /*boundary*/0, 195 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 196 /*highaddr*/BUS_SPACE_MAXADDR, 197 /*filter*/NULL, /*filterarg*/NULL, 198 /*maxsize*/MAXBSIZE, 199 /*nsegments*/AHC_NSEG, 200 /*maxsegsz*/AHC_MAXTRANSFER_SIZE, 201 /*flags*/BUS_DMA_ALLOCNOW, &ahc->dmat); 202 203 if (error != 0) { 204 printf("%s: Could not allocate DMA tag - error %d\n", 205 ahc_name(ahc), error); 206 ahc_free(ahc); 207 return -1; 208 } 209 210 211 eisa_reg_start(e_dev); 212 if (eisa_reg_iospace(e_dev, iospace)) { 213 ahc_free(ahc); 214 return -1; 215 } 216 217 if (ahc_reset(ahc) != 0) { 218 ahc_free(ahc); 219 return -1; 220 } 221 222 /* 223 * The IRQMS bit enables level sensitive interrupts. Only allow 224 * IRQ sharing if it's set. 225 */ 226 if (eisa_reg_intr(e_dev, irq, ahc_intr, (void *)ahc, &cam_imask, 227 /*shared ==*/ahc->pause & IRQMS)) { 228 ahc_free(ahc); 229 return -1; 230 } 231 eisa_reg_end(e_dev); 232 233 /* 234 * Tell the user what type of interrupts we're using. 235 * usefull for debugging irq problems 236 */ 237 if (bootverbose) { 238 printf("%s: Using %s Interrupts\n", 239 ahc_name(ahc), 240 ahc->pause & IRQMS ? 241 "Level Sensitive" : "Edge Triggered"); 242 } 243 244 /* 245 * Now that we know we own the resources we need, do the 246 * card initialization. 247 * 248 * First, the aic7770 card specific setup. 249 */ 250 switch (chip & (AHC_EISA|AHC_VL)) { 251 case AHC_EISA: 252 { 253 u_int biosctrl; 254 u_int scsiconf; 255 u_int scsiconf1; 256#if DEBUG 257 int i; 258#endif 259 260 biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); 261 scsiconf = ahc_inb(ahc, SCSICONF); 262 scsiconf1 = ahc_inb(ahc, SCSICONF + 1); 263 264#if DEBUG 265 for (i = TARG_SCSIRATE; i <= HA_274_BIOSCTRL; i+=8) { 266 printf("0x%x, 0x%x, 0x%x, 0x%x, " 267 "0x%x, 0x%x, 0x%x, 0x%x\n", 268 ahc_inb(ahc, i), 269 ahc_inb(ahc, i+1), 270 ahc_inb(ahc, i+2), 271 ahc_inb(ahc, i+3), 272 ahc_inb(ahc, i+4), 273 ahc_inb(ahc, i+5), 274 ahc_inb(ahc, i+6), 275 ahc_inb(ahc, i+7)); 276 } 277#endif 278 279 /* Get the primary channel information */ 280 if ((biosctrl & CHANNEL_B_PRIMARY) != 0) 281 ahc->flags |= AHC_CHANNEL_B_PRIMARY; 282 283 if ((biosctrl & BIOSMODE) == BIOSDISABLED) { 284 ahc->flags |= AHC_USEDEFAULTS; 285 } else { 286 if ((ahc->features & AHC_WIDE) != 0) { 287 ahc->our_id = scsiconf1 & HWSCSIID; 288 if (scsiconf & TERM_ENB) 289 ahc->flags |= AHC_TERM_ENB_A; 290 } else { 291 ahc->our_id = scsiconf & HSCSIID; 292 ahc->our_id_b = scsiconf1 & HSCSIID; 293 if (scsiconf & TERM_ENB) 294 ahc->flags |= AHC_TERM_ENB_A; 295 if (scsiconf1 & TERM_ENB) 296 ahc->flags |= AHC_TERM_ENB_B; 297 } 298 } 299 /* 300 * We have no way to tell, so assume extended 301 * translation is enabled. 302 */ 303 ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; 304 break; 305 } 306 case AHC_VL: 307 { 308 aha2840_load_seeprom(ahc); 309 break; 310 } 311 default: 312 break; 313 } 314 315 /* 316 * See if we have a Rev E or higher aic7770. Anything below a 317 * Rev E will have a R/O autoflush disable configuration bit. 318 */ 319 { 320 char *id_string; 321 u_int8_t sblkctl; 322 u_int8_t sblkctl_orig; 323 324 sblkctl_orig = ahc_inb(ahc, SBLKCTL); 325 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; 326 ahc_outb(ahc, SBLKCTL, sblkctl); 327 sblkctl = ahc_inb(ahc, SBLKCTL); 328 if (sblkctl != sblkctl_orig) { 329 id_string = "aic7770 >= Rev E, "; 330 /* 331 * Ensure autoflush is enabled 332 */ 333 sblkctl &= ~AUTOFLUSHDIS; 334 ahc_outb(ahc, SBLKCTL, sblkctl); 335 336 } else 337 id_string = "aic7770 <= Rev C, "; 338 339 printf("%s: %s", ahc_name(ahc), id_string); 340 } 341 342 /* Setup the FIFO threshold and the bus off time */ 343 { 344 u_int8_t hostconf = ahc_inb(ahc, HOSTCONF); 345 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); 346 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); 347 } 348 349 /* 350 * Generic aic7xxx initialization. 351 */ 352 if (ahc_init(ahc)) { 353 ahc_free(ahc); 354 /* 355 * The board's IRQ line is not yet enabled so it's safe 356 * to release the irq. 357 */ 358 eisa_release_intr(e_dev, irq, ahc_intr); 359 return -1; 360 } 361 362 /* 363 * Enable the board's BUS drivers 364 */ 365 ahc_outb(ahc, BCTL, ENABLE); 366 367 /* 368 * Enable our interrupt handler. 369 */ 370 if (eisa_enable_intr(e_dev, irq)) { 371 ahc_free(ahc); 372 eisa_release_intr(e_dev, irq, ahc_intr); 373 return -1; 374 } 375 376 /* Attach sub-devices - always succeeds */ 377 ahc_attach(ahc); 378 379 return 0; 380} 381 382/* 383 * Read the 284x SEEPROM. 384 */ 385static void 386aha2840_load_seeprom(struct ahc_softc *ahc) 387{ 388 struct seeprom_descriptor sd; 389 struct seeprom_config sc; 390 u_int16_t checksum = 0; 391 u_int8_t scsi_conf; 392 int have_seeprom; 393 394 sd.sd_tag = ahc->tag; 395 sd.sd_bsh = ahc->bsh; 396 sd.sd_control_offset = SEECTL_2840; 397 sd.sd_status_offset = STATUS_2840; 398 sd.sd_dataout_offset = STATUS_2840; 399 sd.sd_chip = C46; 400 sd.sd_MS = 0; 401 sd.sd_RDY = EEPROM_TF; 402 sd.sd_CS = CS_2840; 403 sd.sd_CK = CK_2840; 404 sd.sd_DO = DO_2840; 405 sd.sd_DI = DI_2840; 406 407 if (bootverbose) 408 printf("%s: Reading SEEPROM...", ahc_name(ahc)); 409 have_seeprom = read_seeprom(&sd, 410 (u_int16_t *)&sc, 411 /*start_addr*/0, 412 sizeof(sc)/2); 413 414 if (have_seeprom) { 415 /* Check checksum */ 416 int i; 417 int maxaddr = (sizeof(sc)/2) - 1; 418 u_int16_t *scarray = (u_int16_t *)≻ 419 420 for (i = 0; i < maxaddr; i++) 421 checksum = checksum + scarray[i]; 422 if (checksum != sc.checksum) { 423 if(bootverbose) 424 printf ("checksum error\n"); 425 have_seeprom = 0; 426 } else if (bootverbose) { 427 printf("done.\n"); 428 } 429 } 430 431 if (!have_seeprom) { 432 if (bootverbose) 433 printf("%s: No SEEPROM available\n", ahc_name(ahc)); 434 ahc->flags |= AHC_USEDEFAULTS; 435 } else { 436 /* 437 * Put the data we've collected down into SRAM 438 * where ahc_init will find it. 439 */ 440 int i; 441 int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; 442 443 for (i = 0; i < max_targ; i++){ 444 u_int8_t target_settings; 445 target_settings = (sc.device_flags[i] & CFXFER) << 4; 446 if (sc.device_flags[i] & CFSYNCH) 447 target_settings |= SOFS; 448 if (sc.device_flags[i] & CFWIDEB) 449 target_settings |= WIDEXFER; 450 if (sc.device_flags[i] & CFDISC) 451 ahc->discenable |= (0x01 << i); 452 ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); 453 } 454 ahc_outb(ahc, DISC_DSB, ~(ahc->discenable & 0xff)); 455 ahc_outb(ahc, DISC_DSB + 1, ~((ahc->discenable >> 8) & 0xff)); 456 457 ahc->our_id = sc.brtime_id & CFSCSIID; 458 459 scsi_conf = (ahc->our_id & 0x7); 460 if (sc.adapter_control & CFSPARITY) 461 scsi_conf |= ENSPCHK; 462 if (sc.adapter_control & CFRESETB) 463 scsi_conf |= RESET_SCSI; 464 465 if (sc.bios_control & CF284XEXTEND) 466 ahc->flags |= AHC_EXTENDED_TRANS_A; 467 /* Set SCSICONF info */ 468 ahc_outb(ahc, SCSICONF, scsi_conf); 469 470 if (sc.adapter_control & CF284XSTERM) 471 ahc->flags |= AHC_TERM_ENB_A; 472 } 473} 474 475#endif /* NEISA > 0 */ 476