1/* $NetBSD: uha_isa.c,v 1.42 2019/11/12 13:10:51 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: uha_isa.c,v 1.42 2019/11/12 13:10:51 msaitoh Exp $"); 34 35#include "opt_ddb.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/device.h> 40#include <sys/kernel.h> 41#include <sys/proc.h> 42 43#include <sys/bus.h> 44#include <sys/intr.h> 45 46#include <dev/scsipi/scsi_all.h> 47#include <dev/scsipi/scsipi_all.h> 48#include <dev/scsipi/scsiconf.h> 49 50#include <dev/isa/isavar.h> 51#include <dev/isa/isadmavar.h> 52 53#include <dev/ic/uhareg.h> 54#include <dev/ic/uhavar.h> 55 56#define UHA_ISA_IOSIZE 16 57 58int uha_isa_probe(device_t, cfdata_t, void *); 59void uha_isa_attach(device_t, device_t, void *); 60 61CFATTACH_DECL_NEW(uha_isa, sizeof(struct uha_softc), 62 uha_isa_probe, uha_isa_attach, NULL, NULL); 63 64#ifndef DDB 65#define Debugger() panic("should call debugger here (uha_isa.c)") 66#endif /* ! DDB */ 67 68int u14_find(bus_space_tag_t, bus_space_handle_t, struct uha_probe_data *); 69void u14_start_mbox(struct uha_softc *, struct uha_mscp *); 70int u14_poll(struct uha_softc *, struct scsipi_xfer *, int); 71int u14_intr(void *); 72void u14_init(struct uha_softc *); 73 74/* 75 * Check the slots looking for a board we recognise 76 * If we find one, note its address (slot) and call 77 * the actual probe routine to check it out. 78 */ 79int 80uha_isa_probe(device_t parent, cfdata_t match, void *aux) 81{ 82 struct isa_attach_args *ia = aux; 83 bus_space_tag_t iot = ia->ia_iot; 84 bus_space_handle_t ioh; 85 struct uha_probe_data upd; 86 int rv; 87 88 if (ia->ia_nio < 1) 89 return (0); 90 if (ia->ia_nirq < 1) 91 return (0); 92 if (ia->ia_ndrq < 1) 93 return (0); 94 95 if (ISA_DIRECT_CONFIG(ia)) 96 return (0); 97 98 /* Disallow wildcarded i/o address. */ 99 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 100 return (0); 101 102 if (bus_space_map(iot, ia->ia_io[0].ir_addr, UHA_ISA_IOSIZE, 0, &ioh)) 103 return (0); 104 105 rv = u14_find(iot, ioh, &upd); 106 107 bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE); 108 109 if (rv) { 110 if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ && 111 ia->ia_irq[0].ir_irq != upd.sc_irq) 112 return (0); 113 if (ia->ia_drq[0].ir_drq != ISA_UNKNOWN_DRQ && 114 ia->ia_drq[0].ir_drq != upd.sc_drq) 115 return (0); 116 117 ia->ia_nio = 1; 118 ia->ia_io[0].ir_size = UHA_ISA_IOSIZE; 119 120 ia->ia_nirq = 1; 121 ia->ia_irq[0].ir_irq = upd.sc_irq; 122 123 ia->ia_ndrq = 1; 124 ia->ia_drq[0].ir_drq = upd.sc_drq; 125 126 ia->ia_niomem = 0; 127 } 128 return (rv); 129} 130 131/* 132 * Attach all the sub-devices we can find 133 */ 134void 135uha_isa_attach(device_t parent, device_t self, void *aux) 136{ 137 struct isa_attach_args *ia = aux; 138 struct uha_softc *sc = device_private(self); 139 bus_space_tag_t iot = ia->ia_iot; 140 bus_dma_tag_t dmat = ia->ia_dmat; 141 bus_space_handle_t ioh; 142 struct uha_probe_data upd; 143 isa_chipset_tag_t ic = ia->ia_ic; 144 int error; 145 146 sc->sc_dev = self; 147 printf("\n"); 148 149 if (bus_space_map(iot, ia->ia_io[0].ir_addr, UHA_ISA_IOSIZE, 0, &ioh)) { 150 aprint_error_dev(sc->sc_dev, "can't map i/o space\n"); 151 return; 152 } 153 154 sc->sc_iot = iot; 155 sc->sc_ioh = ioh; 156 sc->sc_dmat = dmat; 157 if (!u14_find(iot, ioh, &upd)) { 158 aprint_error_dev(sc->sc_dev, "u14_find failed\n"); 159 return; 160 } 161 162 if (upd.sc_drq != -1) { 163 sc->sc_dmaflags = 0; 164 if ((error = isa_dmacascade(ic, upd.sc_drq)) != 0) { 165 aprint_error_dev(sc->sc_dev, "unable to cascade DRQ, error = %d\n", error); 166 return; 167 } 168 } else { 169 /* 170 * We have a VLB controller, and can do 32-bit DMA. 171 */ 172 sc->sc_dmaflags = ISABUS_DMA_32BIT; 173 } 174 175 sc->sc_ih = isa_intr_establish(ic, upd.sc_irq, IST_EDGE, IPL_BIO, 176 u14_intr, sc); 177 if (sc->sc_ih == NULL) { 178 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 179 return; 180 } 181 182 /* Save function pointers for later use. */ 183 sc->start_mbox = u14_start_mbox; 184 sc->poll = u14_poll; 185 sc->init = u14_init; 186 187 uha_attach(sc, &upd); 188} 189 190/* 191 * Start the board, ready for normal operation 192 */ 193int 194u14_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct uha_probe_data *sc) 195{ 196 u_int16_t model, config; 197 int irq, drq; 198 int resetcount = 4000; /* 4 secs? */ 199 200 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) | 201 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0); 202 if ((model & 0xfff0) != 0x5640) 203 return (0); 204 205 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) | 206 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0); 207 208 switch (model & 0x000f) { 209 case 0x0000: 210 switch (config & U14_DMA_MASK) { 211 case U14_DMA_CH5: 212 drq = 5; 213 break; 214 case U14_DMA_CH6: 215 drq = 6; 216 break; 217 case U14_DMA_CH7: 218 drq = 7; 219 break; 220 default: 221 printf("u14_find: illegal drq setting %x\n", 222 config & U14_DMA_MASK); 223 return (0); 224 } 225 break; 226 case 0x0001: 227 /* This is a 34f, and doesn't need an ISA DMA channel. */ 228 drq = -1; 229 break; 230 default: 231 printf("u14_find: unknown model %x\n", model); 232 return (0); 233 } 234 235 switch (config & U14_IRQ_MASK) { 236 case U14_IRQ10: 237 irq = 10; 238 break; 239 case U14_IRQ11: 240 irq = 11; 241 break; 242 case U14_IRQ14: 243 irq = 14; 244 break; 245 case U14_IRQ15: 246 irq = 15; 247 break; 248 default: 249 printf("u14_find: illegal irq setting %x\n", 250 config & U14_IRQ_MASK); 251 return (0); 252 } 253 254 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST); 255 256 while (--resetcount) { 257 if (bus_space_read_1(iot, ioh, U14_LINT)) 258 break; 259 delay(1000); /* 1 mSec per loop */ 260 } 261 if (!resetcount) { 262 printf("u14_find: board timed out during reset\n"); 263 return (0); 264 } 265 266 /* if we want to fill in softc, do so now */ 267 if (sc) { 268 sc->sc_irq = irq; 269 sc->sc_drq = drq; 270 sc->sc_scsi_dev = config & U14_HOSTID_MASK; 271 } 272 273 return (1); 274} 275 276/* 277 * Function to send a command out through a mailbox 278 */ 279void 280u14_start_mbox(struct uha_softc *sc, struct uha_mscp *mscp) 281{ 282 bus_space_tag_t iot = sc->sc_iot; 283 bus_space_handle_t ioh = sc->sc_ioh; 284 int spincount = 100000; /* 1s should be enough */ 285 286 while (--spincount) { 287 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0) 288 break; 289 delay(100); 290 } 291 if (!spincount) { 292 aprint_error_dev(sc->sc_dev, "uha_start_mbox, board not responding\n"); 293 Debugger(); 294 } 295 296 bus_space_write_4(iot, ioh, U14_OGMPTR, 297 sc->sc_dmamap_mscp->dm_segs[0].ds_addr + UHA_MSCP_OFF(mscp)); 298 if (mscp->flags & MSCP_ABORT) 299 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT); 300 else 301 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL); 302 303 if ((mscp->xs->xs_control & XS_CTL_POLL) == 0) 304 callout_reset(&mscp->xs->xs_callout, 305 mstohz(mscp->timeout), uha_timeout, mscp); 306} 307 308/* 309 * Function to poll for command completion when in poll mode. 310 * 311 * wait = timeout in msec 312 */ 313int 314u14_poll(struct uha_softc *sc, struct scsipi_xfer *xs, int count) 315{ 316 bus_space_tag_t iot = sc->sc_iot; 317 bus_space_handle_t ioh = sc->sc_ioh; 318 319 while (count) { 320 /* 321 * If we had interrupts enabled, would we 322 * have got an interrupt? 323 */ 324 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) 325 u14_intr(sc); 326 if (xs->xs_status & XS_STS_DONE) 327 return (0); 328 delay(1000); 329 count--; 330 } 331 return (1); 332} 333 334/* 335 * Catch an interrupt from the adaptor 336 */ 337int 338u14_intr(void *arg) 339{ 340 struct uha_softc *sc = arg; 341 bus_space_tag_t iot = sc->sc_iot; 342 bus_space_handle_t ioh = sc->sc_ioh; 343 struct uha_mscp *mscp; 344 u_char uhastat; 345 u_long mboxval; 346 347#ifdef UHADEBUG 348 printf("%s: uhaintr ", device_xname(sc->sc_dev)); 349#endif /*UHADEBUG */ 350 351 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 352 return (0); 353 354 for (;;) { 355 /* 356 * First get all the information and then 357 * acknowledge the interrupt 358 */ 359 uhastat = bus_space_read_1(iot, ioh, U14_SINT); 360 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR); 361 /* XXX Send an ABORT_ACK instead? */ 362 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK); 363 364#ifdef UHADEBUG 365 printf("status = 0x%x ", uhastat); 366#else 367 __USE(uhastat); 368#endif /*UHADEBUG*/ 369 370 /* 371 * Process the completed operation 372 */ 373 mscp = uha_mscp_phys_kv(sc, mboxval); 374 if (!mscp) { 375 printf("%s: BAD MSCP RETURNED!\n", 376 device_xname(sc->sc_dev)); 377 continue; /* whatever it was, it'll timeout */ 378 } 379 380 callout_stop(&mscp->xs->xs_callout); 381 uha_done(sc, mscp); 382 383 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 384 return (1); 385 } 386} 387 388void 389u14_init(struct uha_softc *sc) 390{ 391 bus_space_tag_t iot = sc->sc_iot; 392 bus_space_handle_t ioh = sc->sc_ioh; 393 394 /* make sure interrupts are enabled */ 395#ifdef UHADEBUG 396 printf("u14_init: lmask=%02x, smask=%02x\n", 397 bus_space_read_1(iot, ioh, U14_LMASK), 398 bus_space_read_1(iot, ioh, U14_SMASK)); 399#endif 400 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */ 401 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */ 402} 403