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