1 /* $OpenBSD: ahc_eisa.c,v 1.24 2021/03/07 06:18:48 jsg 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.24 2021/03/07 06:18:48 jsg 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(bus_space_tag_t iot, bus_space_handle_t ioh) 71 { 72 int irq; 73 u_char intdef; 74 u_char hcntrl; 75 76 /* Pause the card preserving the IRQ type */ 77 hcntrl = bus_space_read_1(iot, ioh, HCNTRL) & IRQMS; 78 bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE); 79 80 intdef = bus_space_read_1(iot, ioh, INTDEF); 81 switch (irq = (intdef & VECTOR)) { 82 case 9: 83 case 10: 84 case 11: 85 case 12: 86 case 14: 87 case 15: 88 break; 89 default: 90 printf("ahc_eisa_irq: illegal irq setting %d\n", intdef); 91 return -1; 92 } 93 94 /* Note that we are going and return (to probe) */ 95 return irq; 96 } 97 98 /* 99 * Check the slots looking for a board we recognise 100 * If we find one, note its address (slot) and call 101 * the actual probe routine to check it out. 102 */ 103 int 104 ahc_eisa_match(struct device *parent, void *match, void *aux) 105 { 106 struct eisa_attach_args *ea = aux; 107 bus_space_tag_t iot = ea->ea_iot; 108 bus_space_handle_t ioh; 109 int irq; 110 111 /* must match one of our known ID strings */ 112 if (strcmp(ea->ea_idstring, "ADP7770") && 113 strcmp(ea->ea_idstring, "ADP7771") 114 #if 0 115 && strcmp(ea->ea_idstring, "ADP7756") /* not EISA, but VL */ 116 && strcmp(ea->ea_idstring, "ADP7757") /* not EISA, but VL */ 117 #endif 118 ) 119 return (0); 120 121 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 122 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 123 return (0); 124 125 irq = ahc_eisa_irq(iot, ioh); 126 127 bus_space_unmap(iot, ioh, AHC_EISA_IOSIZE); 128 129 return (irq >= 0); 130 } 131 132 void 133 ahc_eisa_attach(struct device *parent, struct device *self, void *aux) 134 { 135 struct ahc_softc *ahc = (void *)self; 136 struct eisa_attach_args *ea = aux; 137 bus_space_tag_t iot = ea->ea_iot; 138 bus_space_handle_t ioh; 139 int irq; 140 eisa_chipset_tag_t ec = ea->ea_ec; 141 eisa_intr_handle_t ih; 142 const char *model, *intrstr; 143 u_int biosctrl; 144 u_int scsiconf; 145 u_int scsiconf1; 146 u_int intdef; 147 int i; 148 149 ahc_set_name(ahc, ahc->sc_dev.dv_xname); 150 ahc_set_unit(ahc, ahc->sc_dev.dv_unit); 151 152 /* set dma tags */ 153 ahc->parent_dmat = ea->ea_dmat; 154 155 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 156 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 157 panic("ahc_eisa_attach: can't map i/o addresses"); 158 if ((irq = ahc_eisa_irq(iot, ioh)) < 0) 159 panic("ahc_eisa_attach: ahc_eisa_irq failed!"); 160 161 if (strcmp(ea->ea_idstring, "ADP7770") == 0) { 162 model = EISA_PRODUCT_ADP7770; 163 } else if (strcmp(ea->ea_idstring, "ADP7771") == 0) { 164 model = EISA_PRODUCT_ADP7771; 165 } else { 166 panic("ahc_eisa_attach: Unknown device type %s", 167 ea->ea_idstring); 168 } 169 printf(": %s\n", model); 170 171 /* 172 * Instead of ahc_alloc() as in FreeBSD, do the few relevant 173 * initializations manually. 174 */ 175 LIST_INIT(&ahc->pending_scbs); 176 for (i = 0; i < AHC_NUM_TARGETS; i++) 177 TAILQ_INIT(&ahc->untagged_queues[i]); 178 179 /* 180 * SCSI_IS_SCSIBUS_B() must returns false until sc_channel_b 181 * has been properly initialized. 182 */ 183 ahc->sc_child_b = NULL; 184 185 ahc->channel = 'A'; 186 ahc->chip = AHC_AIC7770|AHC_EISA; 187 ahc->features = AHC_AIC7770_FE; 188 ahc->bugs |= AHC_TMODE_WIDEODD_BUG; 189 ahc->flags |= AHC_PAGESCBS; 190 ahc->tag = iot; 191 ahc->bsh = ioh; 192 ahc->bus_chip_init = ahc_chip_init; 193 ahc->instruction_ram_size = 512; 194 195 if (ahc_softc_init(ahc) != 0) 196 return; 197 198 if (ahc_reset(ahc, /*reinit*/FALSE) != 0) 199 return; 200 201 /* See if we are edge triggered */ 202 intdef = ahc_inb(ahc, INTDEF); 203 if ((intdef & EDGE_TRIG) != 0) 204 ahc->flags |= AHC_EDGE_INTERRUPT; 205 206 if (eisa_intr_map(ec, irq, &ih)) { 207 printf("%s: couldn't map interrupt (%d)\n", 208 ahc->sc_dev.dv_xname, irq); 209 return; 210 } 211 212 /* 213 * Tell the user what type of interrupts we're using. 214 * useful for debugging irq problems 215 */ 216 if (bootverbose) { 217 printf("%s: Using %s Interrupts\n", 218 ahc_name(ahc), 219 ahc->pause & IRQMS ? 220 "Level Sensitive" : "Edge Triggered"); 221 } 222 223 /* 224 * Now that we know we own the resources we need, do the 225 * card initialization. 226 * 227 * First, the aic7770 card specific setup. 228 */ 229 biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); 230 scsiconf = ahc_inb(ahc, SCSICONF); 231 scsiconf1 = ahc_inb(ahc, SCSICONF + 1); 232 233 /* Get the primary channel information */ 234 if ((biosctrl & CHANNEL_B_PRIMARY) != 0) 235 ahc->flags |= AHC_PRIMARY_CHANNEL; 236 237 if ((biosctrl & BIOSMODE) == BIOSDISABLED) { 238 ahc->flags |= AHC_USEDEFAULTS; 239 } else if ((ahc->features & AHC_WIDE) != 0) { 240 ahc->our_id = scsiconf1 & HWSCSIID; 241 if (scsiconf & TERM_ENB) 242 ahc->flags |= AHC_TERM_ENB_A; 243 } else { 244 ahc->our_id = scsiconf & HSCSIID; 245 ahc->our_id_b = scsiconf1 & HSCSIID; 246 if (scsiconf & TERM_ENB) 247 ahc->flags |= AHC_TERM_ENB_A; 248 if (scsiconf1 & TERM_ENB) 249 ahc->flags |= AHC_TERM_ENB_B; 250 } 251 /* 252 * We have no way to tell, so assume extended 253 * translation is enabled. 254 */ 255 256 ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; 257 258 /* 259 * See if we have a Rev E or higher aic7770. Anything below a 260 * Rev E will have a R/O autoflush disable configuration bit. 261 * It's still not clear exactly what is different about the Rev E. 262 * We think it allows 8 bit entries in the QOUTFIFO to support 263 * "paging" SCBs so you can have more than 4 commands active at 264 * once. 265 */ 266 { 267 char *id_string; 268 u_char sblkctl; 269 u_char sblkctl_orig; 270 271 sblkctl_orig = ahc_inb(ahc, SBLKCTL); 272 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; 273 ahc_outb(ahc, SBLKCTL, sblkctl); 274 sblkctl = ahc_inb(ahc, SBLKCTL); 275 if (sblkctl != sblkctl_orig) { 276 id_string = "aic7770 >= Rev E"; 277 /* 278 * Ensure autoflush is enabled 279 */ 280 sblkctl &= ~AUTOFLUSHDIS; 281 ahc_outb(ahc, SBLKCTL, sblkctl); 282 283 /* Allow paging on this adapter */ 284 ahc->flags |= AHC_PAGESCBS; 285 } else 286 id_string = "aic7770 <= Rev C"; 287 288 if (bootverbose) 289 printf("%s: %s\n", ahc_name(ahc), id_string); 290 } 291 292 /* Setup the FIFO threshold and the bus off time */ 293 { 294 u_char hostconf = ahc_inb(ahc, HOSTCONF); 295 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); 296 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); 297 } 298 299 /* 300 * Generic aic7xxx initialization. 301 */ 302 if (ahc_init(ahc)) { 303 ahc_free(ahc); 304 return; 305 } 306 307 /* 308 * Link this softc in with all other ahc instances. 309 */ 310 ahc_softc_insert(ahc); 311 312 /* 313 * Enable the board's BUS drivers 314 */ 315 ahc_outb(ahc, BCTL, ENABLE); 316 317 intrstr = eisa_intr_string(ec, ih); 318 /* 319 * The IRQMS bit enables level sensitive interrupts only allow 320 * IRQ sharing if its set. 321 */ 322 ahc->ih = eisa_intr_establish(ec, ih, 323 ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, 324 ahc_platform_intr, ahc, ahc->sc_dev.dv_xname); 325 if (ahc->ih == NULL) { 326 printf("%s: couldn't establish interrupt", 327 ahc->sc_dev.dv_xname); 328 if (intrstr != NULL) 329 printf(" at %s", intrstr); 330 printf("\n"); 331 ahc_free(ahc); 332 return; 333 } 334 if (intrstr != NULL) 335 printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname, 336 intrstr); 337 338 ahc_intr_enable(ahc, TRUE); 339 340 /* Attach sub-devices - always succeeds */ 341 ahc_attach(ahc); 342 343 } 344