1 /* $OpenBSD: ahc_eisa.c,v 1.21 2012/05/12 21:54:39 miod Exp $ */ 2 /* $NetBSD: ahc_eisa.c,v 1.10 1996/10/21 22:30:58 thorpej Exp $ */ 3 4 /* 5 * Product specific probe and attach routines for: 6 * 27/284X and aic7770 motherboard SCSI controllers 7 * 8 * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice immediately at the beginning of the file, without modification, 16 * this list of conditions, and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $Id: ahc_eisa.c,v 1.21 2012/05/12 21:54:39 miod Exp $ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <machine/bus.h> 43 #include <machine/intr.h> 44 45 #include <scsi/scsi_all.h> 46 #include <scsi/scsiconf.h> 47 48 #include <dev/eisa/eisareg.h> 49 #include <dev/eisa/eisavar.h> 50 #include <dev/eisa/eisadevs.h> 51 #include <dev/ic/aic7xxx_openbsd.h> 52 #include <dev/ic/aic7xxx_inline.h> 53 54 #define AHC_EISA_SLOT_OFFSET 0xc00 55 #define AHC_EISA_IOSIZE 0x100 56 57 int ahc_eisa_irq(bus_space_tag_t, bus_space_handle_t); 58 int ahc_eisa_match(struct device *, void *, void *); 59 void ahc_eisa_attach(struct device *, struct device *, void *); 60 61 62 struct cfattach ahc_eisa_ca = { 63 sizeof(struct ahc_softc), ahc_eisa_match, ahc_eisa_attach 64 }; 65 66 /* 67 * Return irq setting of the board, otherwise -1. 68 */ 69 int 70 ahc_eisa_irq(iot, ioh) 71 bus_space_tag_t iot; 72 bus_space_handle_t ioh; 73 { 74 int irq; 75 u_char intdef; 76 u_char hcntrl; 77 78 /* Pause the card preserving the IRQ type */ 79 hcntrl = bus_space_read_1(iot, ioh, HCNTRL) & IRQMS; 80 bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE); 81 82 intdef = bus_space_read_1(iot, ioh, INTDEF); 83 switch (irq = (intdef & VECTOR)) { 84 case 9: 85 case 10: 86 case 11: 87 case 12: 88 case 14: 89 case 15: 90 break; 91 default: 92 printf("ahc_eisa_irq: illegal irq setting %d\n", intdef); 93 return -1; 94 } 95 96 /* Note that we are going and return (to probe) */ 97 return irq; 98 } 99 100 /* 101 * Check the slots looking for a board we recognise 102 * If we find one, note its address (slot) and call 103 * the actual probe routine to check it out. 104 */ 105 int 106 ahc_eisa_match(parent, match, aux) 107 struct device *parent; 108 void *match, *aux; 109 { 110 struct eisa_attach_args *ea = aux; 111 bus_space_tag_t iot = ea->ea_iot; 112 bus_space_handle_t ioh; 113 int irq; 114 115 /* must match one of our known ID strings */ 116 if (strcmp(ea->ea_idstring, "ADP7770") && 117 strcmp(ea->ea_idstring, "ADP7771") 118 #if 0 119 && strcmp(ea->ea_idstring, "ADP7756") /* not EISA, but VL */ 120 && strcmp(ea->ea_idstring, "ADP7757") /* not EISA, but VL */ 121 #endif 122 ) 123 return (0); 124 125 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 126 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 127 return (0); 128 129 irq = ahc_eisa_irq(iot, ioh); 130 131 bus_space_unmap(iot, ioh, AHC_EISA_IOSIZE); 132 133 return (irq >= 0); 134 } 135 136 void 137 ahc_eisa_attach(parent, self, aux) 138 struct device *parent, *self; 139 void *aux; 140 { 141 struct ahc_softc *ahc = (void *)self; 142 struct eisa_attach_args *ea = aux; 143 bus_space_tag_t iot = ea->ea_iot; 144 bus_space_handle_t ioh; 145 int irq; 146 eisa_chipset_tag_t ec = ea->ea_ec; 147 eisa_intr_handle_t ih; 148 const char *model, *intrstr; 149 u_int biosctrl; 150 u_int scsiconf; 151 u_int scsiconf1; 152 u_int intdef; 153 int i; 154 155 ahc_set_name(ahc, ahc->sc_dev.dv_xname); 156 ahc_set_unit(ahc, ahc->sc_dev.dv_unit); 157 158 /* set dma tags */ 159 ahc->parent_dmat = ea->ea_dmat; 160 161 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 162 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 163 panic("ahc_eisa_attach: can't map i/o addresses"); 164 if ((irq = ahc_eisa_irq(iot, ioh)) < 0) 165 panic("ahc_eisa_attach: ahc_eisa_irq failed!"); 166 167 if (strcmp(ea->ea_idstring, "ADP7770") == 0) { 168 model = EISA_PRODUCT_ADP7770; 169 } else if (strcmp(ea->ea_idstring, "ADP7771") == 0) { 170 model = EISA_PRODUCT_ADP7771; 171 } else { 172 panic("ahc_eisa_attach: Unknown device type %s", 173 ea->ea_idstring); 174 } 175 printf(": %s\n", model); 176 177 /* 178 * Instead of ahc_alloc() as in FreeBSD, do the few relevant 179 * initializations manually. 180 */ 181 LIST_INIT(&ahc->pending_scbs); 182 for (i = 0; i < AHC_NUM_TARGETS; i++) 183 TAILQ_INIT(&ahc->untagged_queues[i]); 184 185 /* 186 * SCSI_IS_SCSIBUS_B() must returns false until sc_channel_b 187 * has been properly initialized. XXX Breaks if >254 scsi buses. 188 */ 189 ahc->sc_channel_b.scsibus = 0xff; 190 191 ahc->channel = 'A'; 192 ahc->chip = AHC_AIC7770|AHC_EISA; 193 ahc->features = AHC_AIC7770_FE; 194 ahc->bugs |= AHC_TMODE_WIDEODD_BUG; 195 ahc->flags |= AHC_PAGESCBS; 196 ahc->tag = iot; 197 ahc->bsh = ioh; 198 ahc->bus_chip_init = ahc_chip_init; 199 ahc->instruction_ram_size = 512; 200 201 if (ahc_softc_init(ahc) != 0) 202 return; 203 204 if (ahc_reset(ahc, /*reinit*/FALSE) != 0) 205 return; 206 207 /* See if we are edge triggered */ 208 intdef = ahc_inb(ahc, INTDEF); 209 if ((intdef & EDGE_TRIG) != 0) 210 ahc->flags |= AHC_EDGE_INTERRUPT; 211 212 if (eisa_intr_map(ec, irq, &ih)) { 213 printf("%s: couldn't map interrupt (%d)\n", 214 ahc->sc_dev.dv_xname, irq); 215 return; 216 } 217 218 /* 219 * Tell the user what type of interrupts we're using. 220 * useful 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 biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); 236 scsiconf = ahc_inb(ahc, SCSICONF); 237 scsiconf1 = ahc_inb(ahc, SCSICONF + 1); 238 239 /* Get the primary channel information */ 240 if ((biosctrl & CHANNEL_B_PRIMARY) != 0) 241 ahc->flags |= AHC_PRIMARY_CHANNEL; 242 243 if ((biosctrl & BIOSMODE) == BIOSDISABLED) { 244 ahc->flags |= AHC_USEDEFAULTS; 245 } else if ((ahc->features & AHC_WIDE) != 0) { 246 ahc->our_id = scsiconf1 & HWSCSIID; 247 if (scsiconf & TERM_ENB) 248 ahc->flags |= AHC_TERM_ENB_A; 249 } else { 250 ahc->our_id = scsiconf & HSCSIID; 251 ahc->our_id_b = scsiconf1 & HSCSIID; 252 if (scsiconf & TERM_ENB) 253 ahc->flags |= AHC_TERM_ENB_A; 254 if (scsiconf1 & TERM_ENB) 255 ahc->flags |= AHC_TERM_ENB_B; 256 } 257 /* 258 * We have no way to tell, so assume extended 259 * translation is enabled. 260 */ 261 262 ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; 263 264 /* 265 * See if we have a Rev E or higher aic7770. Anything below a 266 * Rev E will have a R/O autoflush disable configuration bit. 267 * It's still not clear exactly what is different about the Rev E. 268 * We think it allows 8 bit entries in the QOUTFIFO to support 269 * "paging" SCBs so you can have more than 4 commands active at 270 * once. 271 */ 272 { 273 char *id_string; 274 u_char sblkctl; 275 u_char sblkctl_orig; 276 277 sblkctl_orig = ahc_inb(ahc, SBLKCTL); 278 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; 279 ahc_outb(ahc, SBLKCTL, sblkctl); 280 sblkctl = ahc_inb(ahc, SBLKCTL); 281 if (sblkctl != sblkctl_orig) { 282 id_string = "aic7770 >= Rev E"; 283 /* 284 * Ensure autoflush is enabled 285 */ 286 sblkctl &= ~AUTOFLUSHDIS; 287 ahc_outb(ahc, SBLKCTL, sblkctl); 288 289 /* Allow paging on this adapter */ 290 ahc->flags |= AHC_PAGESCBS; 291 } else 292 id_string = "aic7770 <= Rev C"; 293 294 if (bootverbose) 295 printf("%s: %s\n", ahc_name(ahc), id_string); 296 } 297 298 /* Setup the FIFO threshold and the bus off time */ 299 { 300 u_char hostconf = ahc_inb(ahc, HOSTCONF); 301 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); 302 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); 303 } 304 305 /* 306 * Generic aic7xxx initialization. 307 */ 308 if (ahc_init(ahc)) { 309 ahc_free(ahc); 310 return; 311 } 312 313 /* 314 * Link this softc in with all other ahc instances. 315 */ 316 ahc_softc_insert(ahc); 317 318 /* 319 * Enable the board's BUS drivers 320 */ 321 ahc_outb(ahc, BCTL, ENABLE); 322 323 intrstr = eisa_intr_string(ec, ih); 324 /* 325 * The IRQMS bit enables level sensitive interrupts only allow 326 * IRQ sharing if its set. 327 */ 328 ahc->ih = eisa_intr_establish(ec, ih, 329 ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, 330 ahc_platform_intr, ahc, ahc->sc_dev.dv_xname); 331 if (ahc->ih == NULL) { 332 printf("%s: couldn't establish interrupt", 333 ahc->sc_dev.dv_xname); 334 if (intrstr != NULL) 335 printf(" at %s", intrstr); 336 printf("\n"); 337 ahc_free(ahc); 338 return; 339 } 340 if (intrstr != NULL) 341 printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname, 342 intrstr); 343 344 ahc_intr_enable(ahc, TRUE); 345 346 /* Attach sub-devices - always succeeds */ 347 ahc_attach(ahc); 348 349 } 350