1 1.80 thorpej /* $NetBSD: wds.c,v 1.80 2022/09/25 17:09:36 thorpej Exp $ */ 2 1.1 mycroft 3 1.1 mycroft /* 4 1.1 mycroft * XXX 5 1.1 mycroft * aborts 6 1.1 mycroft * resets 7 1.1 mycroft */ 8 1.1 mycroft 9 1.61 perry /*- 10 1.30 thorpej * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 11 1.19 thorpej * All rights reserved. 12 1.61 perry * 13 1.19 thorpej * This code is derived from software contributed to The NetBSD Foundation 14 1.19 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 15 1.19 thorpej * NASA Ames Research Center. 16 1.61 perry * 17 1.61 perry * Redistribution and use in source and binary forms, with or without 18 1.19 thorpej * modification, are permitted provided that the following conditions 19 1.19 thorpej * are met: 20 1.19 thorpej * 1. Redistributions of source code must retain the above copyright 21 1.19 thorpej * notice, this list of conditions and the following disclaimer. 22 1.19 thorpej * 2. Redistributions in binary form must reproduce the above copyright 23 1.19 thorpej * notice, this list of conditions and the following disclaimer in the 24 1.19 thorpej * documentation and/or other materials provided with the distribution. 25 1.19 thorpej * 26 1.19 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 1.19 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 1.19 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 1.19 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 1.19 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 1.19 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 1.19 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 1.19 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 1.19 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 1.19 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 1.19 thorpej * POSSIBILITY OF SUCH DAMAGE. 37 1.19 thorpej */ 38 1.19 thorpej 39 1.1 mycroft /* 40 1.1 mycroft * Copyright (c) 1994, 1995 Julian Highfield. All rights reserved. 41 1.15 mycroft * Portions copyright (c) 1994, 1996, 1997 42 1.15 mycroft * Charles M. Hannum. All rights reserved. 43 1.1 mycroft * 44 1.1 mycroft * Redistribution and use in source and binary forms, with or without 45 1.1 mycroft * modification, are permitted provided that the following conditions 46 1.1 mycroft * are met: 47 1.1 mycroft * 1. Redistributions of source code must retain the above copyright 48 1.1 mycroft * notice, this list of conditions and the following disclaimer. 49 1.1 mycroft * 2. Redistributions in binary form must reproduce the above copyright 50 1.1 mycroft * notice, this list of conditions and the following disclaimer in the 51 1.1 mycroft * documentation and/or other materials provided with the distribution. 52 1.1 mycroft * 3. All advertising materials mentioning features or use of this software 53 1.1 mycroft * must display the following acknowledgement: 54 1.1 mycroft * This product includes software developed by Julian Highfield. 55 1.1 mycroft * 4. The name of the author may not be used to endorse or promote products 56 1.1 mycroft * derived from this software without specific prior written permission. 57 1.1 mycroft * 58 1.1 mycroft * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 59 1.1 mycroft * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 1.1 mycroft * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 61 1.1 mycroft * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 62 1.1 mycroft * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 63 1.1 mycroft * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 64 1.1 mycroft * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 65 1.1 mycroft * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 66 1.1 mycroft * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 67 1.1 mycroft * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 1.1 mycroft */ 69 1.1 mycroft 70 1.1 mycroft /* 71 1.1 mycroft * This driver is for the WD7000 family of SCSI controllers: 72 1.1 mycroft * the WD7000-ASC, a bus-mastering DMA controller, 73 1.1 mycroft * the WD7000-FASST2, an -ASC with new firmware and scatter-gather, 74 1.1 mycroft * and the WD7000-ASE, which was custom manufactured for Apollo 75 1.1 mycroft * workstations and seems to include an -ASC as well as floppy 76 1.1 mycroft * and ESDI interfaces. 77 1.1 mycroft * 78 1.1 mycroft * Loosely based on Theo Deraadt's unfinished attempt. 79 1.1 mycroft */ 80 1.46 lukem 81 1.46 lukem #include <sys/cdefs.h> 82 1.80 thorpej __KERNEL_RCSID(0, "$NetBSD: wds.c,v 1.80 2022/09/25 17:09:36 thorpej Exp $"); 83 1.46 lukem 84 1.46 lukem #include "opt_ddb.h" 85 1.46 lukem 86 1.46 lukem #undef WDSDIAG 87 1.46 lukem #ifdef DDB 88 1.46 lukem #define integrate 89 1.46 lukem #else 90 1.46 lukem #define integrate static inline 91 1.46 lukem #endif 92 1.1 mycroft 93 1.1 mycroft #include <sys/param.h> 94 1.1 mycroft #include <sys/systm.h> 95 1.1 mycroft #include <sys/kernel.h> 96 1.1 mycroft #include <sys/errno.h> 97 1.1 mycroft #include <sys/ioctl.h> 98 1.1 mycroft #include <sys/device.h> 99 1.1 mycroft #include <sys/buf.h> 100 1.1 mycroft #include <sys/proc.h> 101 1.1 mycroft 102 1.67 ad #include <sys/bus.h> 103 1.67 ad #include <sys/intr.h> 104 1.1 mycroft 105 1.18 bouyer #include <dev/scsipi/scsi_all.h> 106 1.18 bouyer #include <dev/scsipi/scsipi_all.h> 107 1.18 bouyer #include <dev/scsipi/scsiconf.h> 108 1.1 mycroft 109 1.1 mycroft #include <dev/isa/isavar.h> 110 1.1 mycroft #include <dev/isa/isadmavar.h> 111 1.15 mycroft 112 1.1 mycroft #include <dev/isa/wdsreg.h> 113 1.3 cgd 114 1.15 mycroft #define WDS_ISA_IOSIZE 8 115 1.15 mycroft 116 1.3 cgd #ifndef DDB 117 1.3 cgd #define Debugger() panic("should call debugger here (wds.c)") 118 1.3 cgd #endif /* ! DDB */ 119 1.1 mycroft 120 1.19 thorpej #define WDS_MAXXFER ((WDS_NSEG - 1) << PGSHIFT) 121 1.19 thorpej 122 1.1 mycroft #define WDS_MBX_SIZE 16 123 1.1 mycroft 124 1.1 mycroft #define WDS_SCB_MAX 32 125 1.1 mycroft #define SCB_HASH_SIZE 32 /* hash table size for phystokv */ 126 1.1 mycroft #define SCB_HASH_SHIFT 9 127 1.1 mycroft #define SCB_HASH(x) ((((long)(x))>>SCB_HASH_SHIFT) & (SCB_HASH_SIZE - 1)) 128 1.1 mycroft 129 1.1 mycroft #define wds_nextmbx(wmb, mbx, mbio) \ 130 1.1 mycroft if ((wmb) == &(mbx)->mbio[WDS_MBX_SIZE - 1]) \ 131 1.1 mycroft (wmb) = &(mbx)->mbio[0]; \ 132 1.1 mycroft else \ 133 1.1 mycroft (wmb)++; 134 1.1 mycroft 135 1.1 mycroft struct wds_mbx { 136 1.1 mycroft struct wds_mbx_out mbo[WDS_MBX_SIZE]; 137 1.1 mycroft struct wds_mbx_in mbi[WDS_MBX_SIZE]; 138 1.1 mycroft struct wds_mbx_out *cmbo; /* Collection Mail Box out */ 139 1.1 mycroft struct wds_mbx_out *tmbo; /* Target Mail Box out */ 140 1.1 mycroft struct wds_mbx_in *tmbi; /* Target Mail Box in */ 141 1.1 mycroft }; 142 1.1 mycroft 143 1.1 mycroft struct wds_softc { 144 1.76 chs device_t sc_dev; 145 1.15 mycroft 146 1.15 mycroft bus_space_tag_t sc_iot; 147 1.15 mycroft bus_space_handle_t sc_ioh; 148 1.19 thorpej bus_dma_tag_t sc_dmat; 149 1.19 thorpej bus_dmamap_t sc_dmamap_mbox; /* maps the mailbox */ 150 1.1 mycroft void *sc_ih; 151 1.1 mycroft 152 1.19 thorpej struct wds_mbx *sc_mbx; 153 1.19 thorpej #define wmbx (sc->sc_mbx) 154 1.1 mycroft struct wds_scb *sc_scbhash[SCB_HASH_SIZE]; 155 1.1 mycroft TAILQ_HEAD(, wds_scb) sc_free_scb, sc_waiting_scb; 156 1.1 mycroft int sc_numscbs, sc_mbofull; 157 1.42 bouyer 158 1.36 thorpej struct scsipi_adapter sc_adapter; 159 1.42 bouyer struct scsipi_channel sc_channel; 160 1.25 thorpej 161 1.15 mycroft int sc_revision; 162 1.19 thorpej int sc_maxsegs; 163 1.15 mycroft }; 164 1.15 mycroft 165 1.15 mycroft struct wds_probe_data { 166 1.15 mycroft #ifdef notyet 167 1.15 mycroft int sc_irq, sc_drq; 168 1.15 mycroft #endif 169 1.1 mycroft int sc_scsi_dev; 170 1.1 mycroft }; 171 1.1 mycroft 172 1.15 mycroft integrate void 173 1.60 perry wds_wait(bus_space_tag_t, bus_space_handle_t, int, int, int); 174 1.60 perry int wds_cmd(bus_space_tag_t, bus_space_handle_t, u_char *, int); 175 1.60 perry integrate void wds_finish_scbs(struct wds_softc *); 176 1.60 perry int wdsintr(void *); 177 1.60 perry integrate void wds_reset_scb(struct wds_softc *, struct wds_scb *); 178 1.60 perry void wds_free_scb(struct wds_softc *, struct wds_scb *); 179 1.60 perry integrate int wds_init_scb(struct wds_softc *, struct wds_scb *); 180 1.60 perry struct wds_scb *wds_get_scb(struct wds_softc *); 181 1.60 perry struct wds_scb *wds_scb_phys_kv(struct wds_softc *, u_long); 182 1.60 perry void wds_queue_scb(struct wds_softc *, struct wds_scb *); 183 1.60 perry void wds_collect_mbo(struct wds_softc *); 184 1.60 perry void wds_start_scbs(struct wds_softc *); 185 1.60 perry void wds_done(struct wds_softc *, struct wds_scb *, u_char); 186 1.60 perry int wds_find(bus_space_tag_t, bus_space_handle_t, struct wds_probe_data *); 187 1.60 perry void wds_attach(struct wds_softc *, struct wds_probe_data *); 188 1.60 perry void wds_init(struct wds_softc *, int); 189 1.60 perry void wds_inquire_setup_information(struct wds_softc *); 190 1.60 perry void wdsminphys(struct buf *); 191 1.60 perry void wds_scsipi_request(struct scsipi_channel *, 192 1.60 perry scsipi_adapter_req_t, void *); 193 1.60 perry int wds_poll(struct wds_softc *, struct scsipi_xfer *, int); 194 1.60 perry int wds_ipoll(struct wds_softc *, struct wds_scb *, int); 195 1.60 perry void wds_timeout(void *); 196 1.60 perry int wds_create_scbs(struct wds_softc *, void *, size_t); 197 1.1 mycroft 198 1.73 cegger int wdsprobe(device_t, cfdata_t, void *); 199 1.73 cegger void wdsattach(device_t, device_t, void *); 200 1.1 mycroft 201 1.76 chs CFATTACH_DECL_NEW(wds, sizeof(struct wds_softc), 202 1.52 thorpej wdsprobe, wdsattach, NULL, NULL); 203 1.1 mycroft 204 1.63 christos #ifdef WDSDEBUG 205 1.63 christos int wds_debug = 0; 206 1.63 christos #endif 207 1.63 christos 208 1.1 mycroft #define WDS_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 209 1.19 thorpej 210 1.1 mycroft integrate void 211 1.77 msaitoh wds_wait(bus_space_tag_t iot, bus_space_handle_t ioh, int port, int mask, 212 1.77 msaitoh int val) 213 1.1 mycroft { 214 1.1 mycroft 215 1.15 mycroft while ((bus_space_read_1(iot, ioh, port) & mask) != val) 216 1.1 mycroft ; 217 1.1 mycroft } 218 1.1 mycroft 219 1.1 mycroft /* 220 1.1 mycroft * Write a command to the board's I/O ports. 221 1.1 mycroft */ 222 1.1 mycroft int 223 1.70 dsl wds_cmd(bus_space_tag_t iot, bus_space_handle_t ioh, u_char *ibuf, int icnt) 224 1.1 mycroft { 225 1.1 mycroft u_char c; 226 1.1 mycroft 227 1.15 mycroft wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 228 1.1 mycroft 229 1.1 mycroft while (icnt--) { 230 1.15 mycroft bus_space_write_1(iot, ioh, WDS_CMD, *ibuf++); 231 1.15 mycroft wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 232 1.15 mycroft c = bus_space_read_1(iot, ioh, WDS_STAT); 233 1.1 mycroft if (c & WDSS_REJ) 234 1.1 mycroft return 1; 235 1.1 mycroft } 236 1.1 mycroft 237 1.1 mycroft return 0; 238 1.1 mycroft } 239 1.1 mycroft 240 1.1 mycroft /* 241 1.1 mycroft * Check for the presence of a WD7000 SCSI controller. 242 1.1 mycroft */ 243 1.1 mycroft int 244 1.73 cegger wdsprobe(device_t parent, cfdata_t match, void *aux) 245 1.1 mycroft { 246 1.15 mycroft struct isa_attach_args *ia = aux; 247 1.15 mycroft bus_space_tag_t iot = ia->ia_iot; 248 1.15 mycroft bus_space_handle_t ioh; 249 1.15 mycroft struct wds_probe_data wpd; 250 1.15 mycroft int rv; 251 1.22 thorpej 252 1.48 thorpej if (ia->ia_nio < 1) 253 1.48 thorpej return (0); 254 1.48 thorpej if (ia->ia_nirq < 1) 255 1.48 thorpej return (0); 256 1.48 thorpej if (ia->ia_ndrq < 1) 257 1.48 thorpej return (0); 258 1.48 thorpej 259 1.48 thorpej if (ISA_DIRECT_CONFIG(ia)) 260 1.48 thorpej return (0); 261 1.48 thorpej 262 1.22 thorpej /* Disallow wildcarded i/o address. */ 263 1.58 drochner if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 264 1.22 thorpej return (0); 265 1.15 mycroft 266 1.48 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, WDS_ISA_IOSIZE, 0, &ioh)) 267 1.15 mycroft return (0); 268 1.15 mycroft 269 1.15 mycroft rv = wds_find(iot, ioh, &wpd); 270 1.15 mycroft 271 1.15 mycroft bus_space_unmap(iot, ioh, WDS_ISA_IOSIZE); 272 1.15 mycroft 273 1.15 mycroft if (rv) { 274 1.15 mycroft #ifdef notyet 275 1.58 drochner if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ && 276 1.48 thorpej ia->ia_irq[0].ir_irq != wpd.sc_irq) 277 1.15 mycroft return (0); 278 1.58 drochner if (ia->ia_drq[0].ir_drq != ISA_UNKNOWN_DRQ && 279 1.48 thorpej ia->ia_drq[0].ir_drq != wpd.sc_drq) 280 1.15 mycroft return (0); 281 1.48 thorpej 282 1.48 thorpej ia->ia_nirq = 1; 283 1.48 thorpej ia->ia_irq[0].ir_irq = wpd.sc_irq; 284 1.48 thorpej 285 1.48 thorpej ia->ia_ndrq = 1; 286 1.48 thorpej ia->ia_drq[0].ir_drq = wpd.sc_drq; 287 1.15 mycroft #else 288 1.58 drochner if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ) 289 1.15 mycroft return (0); 290 1.58 drochner if (ia->ia_drq[0].ir_drq == ISA_UNKNOWN_DRQ) 291 1.15 mycroft return (0); 292 1.48 thorpej 293 1.48 thorpej ia->ia_nirq = 1; 294 1.48 thorpej ia->ia_ndrq = 1; 295 1.1 mycroft #endif 296 1.48 thorpej ia->ia_nio = 1; 297 1.48 thorpej ia->ia_io[0].ir_size = WDS_ISA_IOSIZE; 298 1.48 thorpej 299 1.48 thorpej ia->ia_niomem = 0; 300 1.15 mycroft } 301 1.15 mycroft return (rv); 302 1.1 mycroft } 303 1.1 mycroft 304 1.1 mycroft /* 305 1.1 mycroft * Attach all available units. 306 1.1 mycroft */ 307 1.1 mycroft void 308 1.73 cegger wdsattach(device_t parent, device_t self, void *aux) 309 1.1 mycroft { 310 1.1 mycroft struct isa_attach_args *ia = aux; 311 1.76 chs struct wds_softc *sc = device_private(self); 312 1.15 mycroft bus_space_tag_t iot = ia->ia_iot; 313 1.15 mycroft bus_space_handle_t ioh; 314 1.15 mycroft struct wds_probe_data wpd; 315 1.15 mycroft isa_chipset_tag_t ic = ia->ia_ic; 316 1.33 thorpej int error; 317 1.15 mycroft 318 1.76 chs sc->sc_dev = self; 319 1.76 chs 320 1.15 mycroft printf("\n"); 321 1.15 mycroft 322 1.48 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, WDS_ISA_IOSIZE, 0, &ioh)) { 323 1.76 chs aprint_error_dev(sc->sc_dev, "can't map i/o space\n"); 324 1.23 thorpej return; 325 1.23 thorpej } 326 1.15 mycroft 327 1.15 mycroft sc->sc_iot = iot; 328 1.15 mycroft sc->sc_ioh = ioh; 329 1.20 mycroft sc->sc_dmat = ia->ia_dmat; 330 1.23 thorpej if (!wds_find(iot, ioh, &wpd)) { 331 1.76 chs aprint_error_dev(sc->sc_dev, "wds_find failed\n"); 332 1.23 thorpej return; 333 1.23 thorpej } 334 1.15 mycroft 335 1.15 mycroft bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN); 336 1.15 mycroft #ifdef notyet 337 1.33 thorpej if (wpd.sc_drq != -1) { 338 1.33 thorpej if ((error = isa_dmacascade(ic, wpd.sc_drq)) != 0) { 339 1.77 msaitoh aprint_error_dev(sc->sc_dev, 340 1.77 msaitoh "unable to cascade DRQ, error = %d\n", error); 341 1.33 thorpej return; 342 1.33 thorpej } 343 1.33 thorpej } 344 1.15 mycroft 345 1.15 mycroft sc->sc_ih = isa_intr_establish(ic, wpd.sc_irq, IST_EDGE, IPL_BIO, 346 1.15 mycroft wdsintr, sc); 347 1.15 mycroft #else 348 1.48 thorpej if ((error = isa_dmacascade(ic, ia->ia_drq[0].ir_drq)) != 0) { 349 1.77 msaitoh aprint_error_dev(sc->sc_dev, 350 1.77 msaitoh "unable to cascade DRQ, error = %d\n", error); 351 1.48 thorpej return; 352 1.33 thorpej } 353 1.1 mycroft 354 1.48 thorpej sc->sc_ih = isa_intr_establish(ic, ia->ia_irq[0].ir_irq, IST_EDGE, 355 1.48 thorpej IPL_BIO, wdsintr, sc); 356 1.15 mycroft #endif 357 1.15 mycroft if (sc->sc_ih == NULL) { 358 1.76 chs aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 359 1.15 mycroft return; 360 1.15 mycroft } 361 1.1 mycroft 362 1.15 mycroft wds_attach(sc, &wpd); 363 1.15 mycroft } 364 1.13 mycroft 365 1.15 mycroft void 366 1.70 dsl wds_attach(struct wds_softc *sc, struct wds_probe_data *wpd) 367 1.15 mycroft { 368 1.61 perry struct scsipi_adapter *adapt = &sc->sc_adapter; 369 1.42 bouyer struct scsipi_channel *chan = &sc->sc_channel; 370 1.1 mycroft 371 1.1 mycroft TAILQ_INIT(&sc->sc_free_scb); 372 1.1 mycroft TAILQ_INIT(&sc->sc_waiting_scb); 373 1.1 mycroft 374 1.1 mycroft /* 375 1.42 bouyer * Fill in the scsipi_adapter. 376 1.36 thorpej */ 377 1.42 bouyer memset(adapt, 0, sizeof(*adapt)); 378 1.76 chs adapt->adapt_dev = sc->sc_dev; 379 1.42 bouyer adapt->adapt_nchannels = 1; 380 1.42 bouyer /* adapt_openings initialized below */ 381 1.42 bouyer adapt->adapt_max_periph = 1; 382 1.42 bouyer adapt->adapt_request = wds_scsipi_request; 383 1.42 bouyer adapt->adapt_minphys = minphys; 384 1.36 thorpej 385 1.36 thorpej /* 386 1.42 bouyer * Fill in the scsipi_channel. 387 1.1 mycroft */ 388 1.42 bouyer memset(chan, 0, sizeof(*chan)); 389 1.42 bouyer chan->chan_adapter = adapt; 390 1.42 bouyer chan->chan_bustype = &scsi_bustype; 391 1.42 bouyer chan->chan_channel = 0; 392 1.42 bouyer chan->chan_ntargets = 8; 393 1.42 bouyer chan->chan_nluns = 8; 394 1.42 bouyer chan->chan_id = wpd->sc_scsi_dev; 395 1.42 bouyer 396 1.42 bouyer wds_init(sc, 0); 397 1.42 bouyer wds_inquire_setup_information(sc); 398 1.42 bouyer 399 1.42 bouyer /* XXX add support for GROW */ 400 1.42 bouyer adapt->adapt_openings = sc->sc_numscbs; 401 1.1 mycroft 402 1.1 mycroft /* 403 1.1 mycroft * ask the adapter what subunits are present 404 1.1 mycroft */ 405 1.79 thorpej config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE); 406 1.1 mycroft } 407 1.1 mycroft 408 1.1 mycroft integrate void 409 1.70 dsl wds_finish_scbs(struct wds_softc *sc) 410 1.1 mycroft { 411 1.1 mycroft struct wds_mbx_in *wmbi; 412 1.1 mycroft struct wds_scb *scb; 413 1.1 mycroft int i; 414 1.1 mycroft 415 1.1 mycroft wmbi = wmbx->tmbi; 416 1.1 mycroft 417 1.1 mycroft if (wmbi->stat == WDS_MBI_FREE) { 418 1.1 mycroft for (i = 0; i < WDS_MBX_SIZE; i++) { 419 1.1 mycroft if (wmbi->stat != WDS_MBI_FREE) { 420 1.12 christos printf("%s: mbi not in round-robin order\n", 421 1.76 chs device_xname(sc->sc_dev)); 422 1.1 mycroft goto AGAIN; 423 1.1 mycroft } 424 1.1 mycroft wds_nextmbx(wmbi, wmbx, mbi); 425 1.1 mycroft } 426 1.1 mycroft #ifdef WDSDIAGnot 427 1.12 christos printf("%s: mbi interrupt with no full mailboxes\n", 428 1.76 chs device_xname(sc->sc_dev)); 429 1.1 mycroft #endif 430 1.1 mycroft return; 431 1.1 mycroft } 432 1.1 mycroft 433 1.1 mycroft AGAIN: 434 1.1 mycroft do { 435 1.1 mycroft scb = wds_scb_phys_kv(sc, phystol(wmbi->scb_addr)); 436 1.1 mycroft if (!scb) { 437 1.12 christos printf("%s: bad mbi scb pointer; skipping\n", 438 1.76 chs device_xname(sc->sc_dev)); 439 1.1 mycroft goto next; 440 1.1 mycroft } 441 1.1 mycroft 442 1.1 mycroft #ifdef WDSDEBUG 443 1.1 mycroft if (wds_debug) { 444 1.63 christos u_char *cp = scb->cmd.xx; 445 1.12 christos printf("op=%x %x %x %x %x %x\n", 446 1.1 mycroft cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 447 1.63 christos printf("stat %x for mbi addr = %p, ", 448 1.1 mycroft wmbi->stat, wmbi); 449 1.63 christos printf("scb addr = %p\n", scb); 450 1.1 mycroft } 451 1.1 mycroft #endif /* WDSDEBUG */ 452 1.1 mycroft 453 1.40 thorpej callout_stop(&scb->xs->xs_callout); 454 1.1 mycroft wds_done(sc, scb, wmbi->stat); 455 1.1 mycroft 456 1.1 mycroft next: 457 1.1 mycroft wmbi->stat = WDS_MBI_FREE; 458 1.1 mycroft wds_nextmbx(wmbi, wmbx, mbi); 459 1.1 mycroft } while (wmbi->stat != WDS_MBI_FREE); 460 1.1 mycroft 461 1.1 mycroft wmbx->tmbi = wmbi; 462 1.1 mycroft } 463 1.1 mycroft 464 1.1 mycroft /* 465 1.1 mycroft * Process an interrupt. 466 1.1 mycroft */ 467 1.1 mycroft int 468 1.70 dsl wdsintr(void *arg) 469 1.1 mycroft { 470 1.1 mycroft struct wds_softc *sc = arg; 471 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 472 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 473 1.5 christos u_char c; 474 1.1 mycroft 475 1.1 mycroft /* Was it really an interrupt from the board? */ 476 1.15 mycroft if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) == 0) 477 1.1 mycroft return 0; 478 1.1 mycroft 479 1.1 mycroft /* Get the interrupt status byte. */ 480 1.15 mycroft c = bus_space_read_1(iot, ioh, WDS_IRQSTAT) & WDSI_MASK; 481 1.1 mycroft 482 1.1 mycroft /* Acknowledge (which resets) the interrupt. */ 483 1.15 mycroft bus_space_write_1(iot, ioh, WDS_IRQACK, 0x00); 484 1.1 mycroft 485 1.1 mycroft switch (c) { 486 1.1 mycroft case WDSI_MSVC: 487 1.1 mycroft wds_finish_scbs(sc); 488 1.1 mycroft break; 489 1.1 mycroft 490 1.1 mycroft case WDSI_MFREE: 491 1.1 mycroft wds_start_scbs(sc); 492 1.1 mycroft break; 493 1.1 mycroft 494 1.1 mycroft default: 495 1.77 msaitoh aprint_error_dev(sc->sc_dev, 496 1.77 msaitoh "unrecognized interrupt type %02x", c); 497 1.1 mycroft break; 498 1.1 mycroft } 499 1.1 mycroft 500 1.1 mycroft return 1; 501 1.1 mycroft } 502 1.1 mycroft 503 1.1 mycroft integrate void 504 1.65 christos wds_reset_scb(struct wds_softc *sc, struct wds_scb *scb) 505 1.1 mycroft { 506 1.1 mycroft 507 1.1 mycroft scb->flags = 0; 508 1.1 mycroft } 509 1.1 mycroft 510 1.1 mycroft /* 511 1.1 mycroft * Free the command structure, the outgoing mailbox and the data buffer. 512 1.1 mycroft */ 513 1.1 mycroft void 514 1.70 dsl wds_free_scb(struct wds_softc *sc, struct wds_scb *scb) 515 1.1 mycroft { 516 1.1 mycroft int s; 517 1.1 mycroft 518 1.1 mycroft s = splbio(); 519 1.1 mycroft wds_reset_scb(sc, scb); 520 1.1 mycroft TAILQ_INSERT_HEAD(&sc->sc_free_scb, scb, chain); 521 1.1 mycroft splx(s); 522 1.1 mycroft } 523 1.1 mycroft 524 1.24 thorpej integrate int 525 1.70 dsl wds_init_scb(struct wds_softc *sc, struct wds_scb *scb) 526 1.1 mycroft { 527 1.19 thorpej bus_dma_tag_t dmat = sc->sc_dmat; 528 1.24 thorpej int hashnum, error; 529 1.1 mycroft 530 1.19 thorpej /* 531 1.19 thorpej * XXX Should we put a DIAGNOSTIC check for multiple 532 1.19 thorpej * XXX SCB inits here? 533 1.19 thorpej */ 534 1.1 mycroft 535 1.43 thorpej memset(scb, 0, sizeof(struct wds_scb)); 536 1.1 mycroft 537 1.1 mycroft /* 538 1.19 thorpej * Create DMA maps for this SCB. 539 1.1 mycroft */ 540 1.24 thorpej error = bus_dmamap_create(dmat, sizeof(struct wds_scb), 1, 541 1.24 thorpej sizeof(struct wds_scb), 0, BUS_DMA_NOWAIT, &scb->dmamap_self); 542 1.24 thorpej if (error) { 543 1.76 chs aprint_error_dev(sc->sc_dev, "can't create scb dmamap_self\n"); 544 1.24 thorpej return (error); 545 1.24 thorpej } 546 1.1 mycroft 547 1.24 thorpej error = bus_dmamap_create(dmat, WDS_MAXXFER, WDS_NSEG, WDS_MAXXFER, 548 1.24 thorpej 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &scb->dmamap_xfer); 549 1.24 thorpej if (error) { 550 1.76 chs aprint_error_dev(sc->sc_dev, "can't create scb dmamap_xfer\n"); 551 1.24 thorpej bus_dmamap_destroy(dmat, scb->dmamap_self); 552 1.24 thorpej return (error); 553 1.24 thorpej } 554 1.1 mycroft 555 1.19 thorpej /* 556 1.19 thorpej * Load the permanent DMA maps. 557 1.19 thorpej */ 558 1.24 thorpej error = bus_dmamap_load(dmat, scb->dmamap_self, scb, 559 1.24 thorpej sizeof(struct wds_scb), NULL, BUS_DMA_NOWAIT); 560 1.24 thorpej if (error) { 561 1.76 chs aprint_error_dev(sc->sc_dev, "can't load scb dmamap_self\n"); 562 1.24 thorpej bus_dmamap_destroy(dmat, scb->dmamap_self); 563 1.24 thorpej bus_dmamap_destroy(dmat, scb->dmamap_xfer); 564 1.24 thorpej return (error); 565 1.24 thorpej } 566 1.1 mycroft 567 1.1 mycroft /* 568 1.1 mycroft * put in the phystokv hash table 569 1.1 mycroft * Never gets taken out. 570 1.1 mycroft */ 571 1.19 thorpej scb->hashkey = scb->dmamap_self->dm_segs[0].ds_addr; 572 1.1 mycroft hashnum = SCB_HASH(scb->hashkey); 573 1.1 mycroft scb->nexthash = sc->sc_scbhash[hashnum]; 574 1.1 mycroft sc->sc_scbhash[hashnum] = scb; 575 1.1 mycroft wds_reset_scb(sc, scb); 576 1.24 thorpej return (0); 577 1.1 mycroft } 578 1.1 mycroft 579 1.1 mycroft /* 580 1.19 thorpej * Create a set of scbs and add them to the free list. 581 1.19 thorpej */ 582 1.19 thorpej int 583 1.70 dsl wds_create_scbs(struct wds_softc *sc, void *mem, size_t size) 584 1.19 thorpej { 585 1.19 thorpej bus_dma_segment_t seg; 586 1.19 thorpej struct wds_scb *scb; 587 1.19 thorpej int rseg, error; 588 1.19 thorpej 589 1.19 thorpej if (sc->sc_numscbs >= WDS_SCB_MAX) 590 1.19 thorpej return (0); 591 1.19 thorpej 592 1.19 thorpej if ((scb = mem) != NULL) 593 1.19 thorpej goto have_mem; 594 1.19 thorpej 595 1.41 thorpej size = PAGE_SIZE; 596 1.41 thorpej error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 597 1.41 thorpej 1, &rseg, BUS_DMA_NOWAIT); 598 1.24 thorpej if (error) { 599 1.77 msaitoh aprint_error_dev(sc->sc_dev, 600 1.77 msaitoh "can't allocate memory for scbs\n"); 601 1.19 thorpej return (error); 602 1.24 thorpej } 603 1.19 thorpej 604 1.19 thorpej error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 605 1.56 christos (void *)&scb, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 606 1.19 thorpej if (error) { 607 1.76 chs aprint_error_dev(sc->sc_dev, "can't map memory for scbs\n"); 608 1.19 thorpej bus_dmamem_free(sc->sc_dmat, &seg, rseg); 609 1.19 thorpej return (error); 610 1.19 thorpej } 611 1.19 thorpej 612 1.19 thorpej have_mem: 613 1.43 thorpej memset(scb, 0, size); 614 1.24 thorpej while (size > sizeof(struct wds_scb) && sc->sc_numscbs < WDS_SCB_MAX) { 615 1.24 thorpej error = wds_init_scb(sc, scb); 616 1.24 thorpej if (error) { 617 1.76 chs aprint_error_dev(sc->sc_dev, "can't initialize scb\n"); 618 1.24 thorpej return (error); 619 1.24 thorpej } 620 1.19 thorpej TAILQ_INSERT_TAIL(&sc->sc_free_scb, scb, chain); 621 1.66 christos scb = (struct wds_scb *)((char *)scb + 622 1.57 drochner ALIGN(sizeof(struct wds_scb))); 623 1.19 thorpej size -= ALIGN(sizeof(struct wds_scb)); 624 1.24 thorpej sc->sc_numscbs++; 625 1.19 thorpej } 626 1.19 thorpej 627 1.19 thorpej return (0); 628 1.19 thorpej } 629 1.19 thorpej 630 1.19 thorpej /* 631 1.1 mycroft * Get a free scb 632 1.1 mycroft * 633 1.1 mycroft * If there are none, see if we can allocate a new one. If so, put it in 634 1.1 mycroft * the hash table too otherwise either return an error or sleep. 635 1.1 mycroft */ 636 1.1 mycroft struct wds_scb * 637 1.70 dsl wds_get_scb(struct wds_softc *sc) 638 1.1 mycroft { 639 1.1 mycroft struct wds_scb *scb; 640 1.1 mycroft int s; 641 1.1 mycroft 642 1.1 mycroft s = splbio(); 643 1.42 bouyer scb = TAILQ_FIRST(&sc->sc_free_scb); 644 1.42 bouyer if (scb != NULL) { 645 1.42 bouyer TAILQ_REMOVE(&sc->sc_free_scb, scb, chain); 646 1.42 bouyer scb->flags |= SCB_ALLOC; 647 1.1 mycroft } 648 1.1 mycroft splx(s); 649 1.1 mycroft return (scb); 650 1.1 mycroft } 651 1.1 mycroft 652 1.1 mycroft struct wds_scb * 653 1.70 dsl wds_scb_phys_kv(struct wds_softc *sc, u_long scb_phys) 654 1.1 mycroft { 655 1.1 mycroft int hashnum = SCB_HASH(scb_phys); 656 1.1 mycroft struct wds_scb *scb = sc->sc_scbhash[hashnum]; 657 1.1 mycroft 658 1.1 mycroft while (scb) { 659 1.1 mycroft if (scb->hashkey == scb_phys) 660 1.1 mycroft break; 661 1.1 mycroft /* XXX Check to see if it matches the sense command block. */ 662 1.1 mycroft if (scb->hashkey == (scb_phys - sizeof(struct wds_cmd))) 663 1.1 mycroft break; 664 1.1 mycroft scb = scb->nexthash; 665 1.1 mycroft } 666 1.21 mycroft return (scb); 667 1.1 mycroft } 668 1.1 mycroft 669 1.1 mycroft /* 670 1.1 mycroft * Queue a SCB to be sent to the controller, and send it if possible. 671 1.1 mycroft */ 672 1.1 mycroft void 673 1.70 dsl wds_queue_scb(struct wds_softc *sc, struct wds_scb *scb) 674 1.1 mycroft { 675 1.1 mycroft 676 1.1 mycroft TAILQ_INSERT_TAIL(&sc->sc_waiting_scb, scb, chain); 677 1.1 mycroft wds_start_scbs(sc); 678 1.1 mycroft } 679 1.1 mycroft 680 1.1 mycroft /* 681 1.1 mycroft * Garbage collect mailboxes that are no longer in use. 682 1.1 mycroft */ 683 1.1 mycroft void 684 1.70 dsl wds_collect_mbo(struct wds_softc *sc) 685 1.1 mycroft { 686 1.1 mycroft struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ 687 1.11 christos #ifdef WDSDIAG 688 1.1 mycroft struct wds_scb *scb; 689 1.11 christos #endif 690 1.1 mycroft 691 1.1 mycroft wmbo = wmbx->cmbo; 692 1.1 mycroft 693 1.1 mycroft while (sc->sc_mbofull > 0) { 694 1.1 mycroft if (wmbo->cmd != WDS_MBO_FREE) 695 1.1 mycroft break; 696 1.1 mycroft 697 1.1 mycroft #ifdef WDSDIAG 698 1.1 mycroft scb = wds_scb_phys_kv(sc, phystol(wmbo->scb_addr)); 699 1.1 mycroft scb->flags &= ~SCB_SENDING; 700 1.1 mycroft #endif 701 1.1 mycroft 702 1.1 mycroft --sc->sc_mbofull; 703 1.1 mycroft wds_nextmbx(wmbo, wmbx, mbo); 704 1.1 mycroft } 705 1.1 mycroft 706 1.1 mycroft wmbx->cmbo = wmbo; 707 1.1 mycroft } 708 1.1 mycroft 709 1.1 mycroft /* 710 1.1 mycroft * Send as many SCBs as we have empty mailboxes for. 711 1.1 mycroft */ 712 1.1 mycroft void 713 1.70 dsl wds_start_scbs(struct wds_softc *sc) 714 1.1 mycroft { 715 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 716 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 717 1.1 mycroft struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ 718 1.1 mycroft struct wds_scb *scb; 719 1.1 mycroft u_char c; 720 1.1 mycroft 721 1.1 mycroft wmbo = wmbx->tmbo; 722 1.1 mycroft 723 1.5 christos while ((scb = sc->sc_waiting_scb.tqh_first) != NULL) { 724 1.1 mycroft if (sc->sc_mbofull >= WDS_MBX_SIZE) { 725 1.1 mycroft wds_collect_mbo(sc); 726 1.1 mycroft if (sc->sc_mbofull >= WDS_MBX_SIZE) { 727 1.1 mycroft c = WDSC_IRQMFREE; 728 1.15 mycroft wds_cmd(iot, ioh, &c, sizeof c); 729 1.1 mycroft break; 730 1.1 mycroft } 731 1.1 mycroft } 732 1.1 mycroft 733 1.1 mycroft TAILQ_REMOVE(&sc->sc_waiting_scb, scb, chain); 734 1.1 mycroft #ifdef WDSDIAG 735 1.1 mycroft scb->flags |= SCB_SENDING; 736 1.1 mycroft #endif 737 1.1 mycroft 738 1.1 mycroft /* Link scb to mbo. */ 739 1.42 bouyer ltophys(scb->dmamap_self->dm_segs[0].ds_addr + 740 1.42 bouyer offsetof(struct wds_scb, cmd), wmbo->scb_addr); 741 1.1 mycroft /* XXX What about aborts? */ 742 1.1 mycroft wmbo->cmd = WDS_MBO_START; 743 1.1 mycroft 744 1.1 mycroft /* Tell the card to poll immediately. */ 745 1.1 mycroft c = WDSC_MSTART(wmbo - wmbx->mbo); 746 1.15 mycroft wds_cmd(sc->sc_iot, sc->sc_ioh, &c, sizeof c); 747 1.1 mycroft 748 1.1 mycroft if ((scb->flags & SCB_POLLED) == 0) 749 1.40 thorpej callout_reset(&scb->xs->xs_callout, 750 1.49 bouyer mstohz(scb->timeout), wds_timeout, scb); 751 1.1 mycroft 752 1.1 mycroft ++sc->sc_mbofull; 753 1.1 mycroft wds_nextmbx(wmbo, wmbx, mbo); 754 1.1 mycroft } 755 1.1 mycroft 756 1.1 mycroft wmbx->tmbo = wmbo; 757 1.1 mycroft } 758 1.1 mycroft 759 1.1 mycroft /* 760 1.1 mycroft * Process the result of a SCSI command. 761 1.1 mycroft */ 762 1.1 mycroft void 763 1.70 dsl wds_done(struct wds_softc *sc, struct wds_scb *scb, u_char stat) 764 1.1 mycroft { 765 1.19 thorpej bus_dma_tag_t dmat = sc->sc_dmat; 766 1.18 bouyer struct scsipi_xfer *xs = scb->xs; 767 1.1 mycroft 768 1.1 mycroft /* XXXXX */ 769 1.1 mycroft 770 1.1 mycroft /* Don't release the SCB if it was an internal command. */ 771 1.1 mycroft if (xs == 0) { 772 1.1 mycroft scb->flags |= SCB_DONE; 773 1.1 mycroft return; 774 1.1 mycroft } 775 1.1 mycroft 776 1.42 bouyer /* 777 1.42 bouyer * If we were a data transfer, unload the map that described 778 1.42 bouyer * the data buffer. 779 1.42 bouyer */ 780 1.42 bouyer if (xs->datalen) { 781 1.42 bouyer bus_dmamap_sync(dmat, scb->dmamap_xfer, 0, 782 1.42 bouyer scb->dmamap_xfer->dm_mapsize, 783 1.42 bouyer (xs->xs_control & XS_CTL_DATA_IN) ? 784 1.42 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 785 1.42 bouyer bus_dmamap_unload(dmat, scb->dmamap_xfer); 786 1.42 bouyer } 787 1.42 bouyer if (xs->error == XS_NOERROR) { 788 1.42 bouyer /* If all went well, or an error is acceptable. */ 789 1.42 bouyer if (stat == WDS_MBI_OK) { 790 1.42 bouyer /* OK, set the result */ 791 1.42 bouyer xs->resid = 0; 792 1.42 bouyer } else { 793 1.42 bouyer /* Check the mailbox status. */ 794 1.42 bouyer switch (stat) { 795 1.42 bouyer case WDS_MBI_OKERR: 796 1.42 bouyer /* 797 1.42 bouyer * SCSI error recorded in scb, 798 1.42 bouyer * counts as WDS_MBI_OK 799 1.42 bouyer */ 800 1.42 bouyer switch (scb->cmd.venderr) { 801 1.42 bouyer case 0x00: 802 1.77 msaitoh aprint_error_dev(sc->sc_dev, 803 1.77 msaitoh "Is this an error?\n"); 804 1.42 bouyer /* Experiment. */ 805 1.42 bouyer xs->error = XS_DRIVER_STUFFUP; 806 1.42 bouyer break; 807 1.42 bouyer case 0x01: 808 1.19 thorpej #if 0 809 1.77 msaitoh aprint_error_dev(sc->sc_dev, 810 1.77 msaitoh "OK, see SCSI error field.\n"); 811 1.19 thorpej #endif 812 1.42 bouyer if (scb->cmd.stat == SCSI_CHECK || 813 1.42 bouyer scb->cmd.stat == SCSI_BUSY) { 814 1.42 bouyer xs->status = scb->cmd.stat; 815 1.42 bouyer xs->error = XS_BUSY; 816 1.42 bouyer } 817 1.42 bouyer break; 818 1.42 bouyer case 0x40: 819 1.19 thorpej #if 0 820 1.42 bouyer printf("%s: DMA underrun!\n", 821 1.76 chs device_xname(sc->sc_dev)); 822 1.19 thorpej #endif 823 1.1 mycroft /* 824 1.42 bouyer * Hits this if the target 825 1.42 bouyer * returns fewer that datalen 826 1.42 bouyer * bytes (eg my CD-ROM, which 827 1.42 bouyer * returns a short version 828 1.42 bouyer * string, or if DMA is 829 1.42 bouyer * turned off etc. 830 1.1 mycroft */ 831 1.42 bouyer xs->resid = 0; 832 1.1 mycroft break; 833 1.42 bouyer default: 834 1.42 bouyer printf("%s: VENDOR ERROR " 835 1.42 bouyer "%02x, scsi %02x\n", 836 1.76 chs device_xname(sc->sc_dev), 837 1.42 bouyer scb->cmd.venderr, 838 1.42 bouyer scb->cmd.stat); 839 1.42 bouyer /* Experiment. */ 840 1.1 mycroft xs->error = XS_DRIVER_STUFFUP; 841 1.1 mycroft break; 842 1.1 mycroft } 843 1.42 bouyer break; 844 1.42 bouyer case WDS_MBI_ETIME: 845 1.42 bouyer /* 846 1.42 bouyer * The documentation isn't clear on 847 1.42 bouyer * what conditions might generate this, 848 1.42 bouyer * but selection timeouts are the only 849 1.42 bouyer * one I can think of. 850 1.42 bouyer */ 851 1.42 bouyer xs->error = XS_SELTIMEOUT; 852 1.42 bouyer break; 853 1.42 bouyer case WDS_MBI_ERESET: 854 1.42 bouyer case WDS_MBI_ETARCMD: 855 1.42 bouyer case WDS_MBI_ERESEL: 856 1.42 bouyer case WDS_MBI_ESEL: 857 1.42 bouyer case WDS_MBI_EABORT: 858 1.42 bouyer case WDS_MBI_ESRESET: 859 1.42 bouyer case WDS_MBI_EHRESET: 860 1.42 bouyer xs->error = XS_DRIVER_STUFFUP; 861 1.42 bouyer break; 862 1.1 mycroft } 863 1.42 bouyer } 864 1.1 mycroft } /* XS_NOERROR */ 865 1.1 mycroft 866 1.1 mycroft wds_free_scb(sc, scb); 867 1.18 bouyer scsipi_done(xs); 868 1.1 mycroft } 869 1.1 mycroft 870 1.1 mycroft int 871 1.77 msaitoh wds_find(bus_space_tag_t iot, bus_space_handle_t ioh, 872 1.77 msaitoh struct wds_probe_data *sc) 873 1.1 mycroft { 874 1.1 mycroft int i; 875 1.1 mycroft 876 1.1 mycroft /* XXXXX */ 877 1.1 mycroft 878 1.1 mycroft /* 879 1.1 mycroft * Sending a command causes the CMDRDY bit to clear. 880 1.1 mycroft */ 881 1.15 mycroft for (i = 5; i; i--) { 882 1.15 mycroft if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0) 883 1.15 mycroft break; 884 1.15 mycroft delay(100); 885 1.1 mycroft } 886 1.15 mycroft if (!i) 887 1.16 marc return 0; 888 1.1 mycroft 889 1.15 mycroft bus_space_write_1(iot, ioh, WDS_CMD, WDSC_NOOP); 890 1.15 mycroft if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0) 891 1.16 marc return 0; 892 1.1 mycroft 893 1.15 mycroft bus_space_write_1(iot, ioh, WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET); 894 1.1 mycroft delay(10000); 895 1.15 mycroft bus_space_write_1(iot, ioh, WDS_HCR, 0x00); 896 1.1 mycroft delay(500000); 897 1.15 mycroft wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 898 1.15 mycroft if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 1) 899 1.15 mycroft if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 7) 900 1.16 marc return 0; 901 1.15 mycroft 902 1.15 mycroft for (i = 2000; i; i--) { 903 1.15 mycroft if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0) 904 1.15 mycroft break; 905 1.15 mycroft delay(100); 906 1.1 mycroft } 907 1.15 mycroft if (!i) 908 1.16 marc return 0; 909 1.1 mycroft 910 1.15 mycroft if (sc) { 911 1.15 mycroft #ifdef notyet 912 1.15 mycroft sc->sc_irq = ...; 913 1.15 mycroft sc->sc_drq = ...; 914 1.15 mycroft #endif 915 1.1 mycroft /* XXX Can we do this better? */ 916 1.1 mycroft sc->sc_scsi_dev = 7; 917 1.1 mycroft } 918 1.1 mycroft 919 1.16 marc return 1; 920 1.1 mycroft } 921 1.1 mycroft 922 1.1 mycroft /* 923 1.1 mycroft * Initialise the board and driver. 924 1.1 mycroft */ 925 1.1 mycroft void 926 1.70 dsl wds_init(struct wds_softc *sc, int isreset) 927 1.1 mycroft { 928 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 929 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 930 1.19 thorpej bus_dma_segment_t seg; 931 1.1 mycroft struct wds_setup init; 932 1.1 mycroft u_char c; 933 1.19 thorpej int i, rseg; 934 1.19 thorpej 935 1.19 thorpej if (isreset) 936 1.19 thorpej goto doinit; 937 1.19 thorpej 938 1.19 thorpej /* 939 1.19 thorpej * Allocate the mailbox. 940 1.19 thorpej */ 941 1.41 thorpej if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, &seg, 1, 942 1.19 thorpej &rseg, BUS_DMA_NOWAIT) || 943 1.41 thorpej bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, 944 1.66 christos (void **)&wmbx, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) 945 1.19 thorpej panic("wds_init: can't create or map mailbox"); 946 1.19 thorpej 947 1.21 mycroft /* 948 1.21 mycroft * Since DMA memory allocation is always rounded up to a 949 1.21 mycroft * page size, create some scbs from the leftovers. 950 1.21 mycroft */ 951 1.66 christos if (wds_create_scbs(sc, ((char *)wmbx) + 952 1.21 mycroft ALIGN(sizeof(struct wds_mbx)), 953 1.41 thorpej PAGE_SIZE - ALIGN(sizeof(struct wds_mbx)))) 954 1.21 mycroft panic("wds_init: can't create scbs"); 955 1.19 thorpej 956 1.19 thorpej /* 957 1.19 thorpej * Create and load the mailbox DMA map. 958 1.19 thorpej */ 959 1.19 thorpej if (bus_dmamap_create(sc->sc_dmat, sizeof(struct wds_mbx), 1, 960 1.19 thorpej sizeof(struct wds_mbx), 0, BUS_DMA_NOWAIT, &sc->sc_dmamap_mbox) || 961 1.19 thorpej bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx, 962 1.19 thorpej sizeof(struct wds_mbx), NULL, BUS_DMA_NOWAIT)) 963 1.55 wiz panic("wds_ionit: can't create or load mailbox DMA map"); 964 1.1 mycroft 965 1.19 thorpej doinit: 966 1.1 mycroft /* 967 1.1 mycroft * Set up initial mail box for round-robin operation. 968 1.1 mycroft */ 969 1.1 mycroft for (i = 0; i < WDS_MBX_SIZE; i++) { 970 1.1 mycroft wmbx->mbo[i].cmd = WDS_MBO_FREE; 971 1.6 mycroft wmbx->mbi[i].stat = WDS_MBI_FREE; 972 1.1 mycroft } 973 1.1 mycroft wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0]; 974 1.1 mycroft wmbx->tmbi = &wmbx->mbi[0]; 975 1.1 mycroft sc->sc_mbofull = 0; 976 1.1 mycroft 977 1.1 mycroft init.opcode = WDSC_INIT; 978 1.42 bouyer init.scsi_id = sc->sc_channel.chan_id; 979 1.1 mycroft init.buson_t = 48; 980 1.1 mycroft init.busoff_t = 24; 981 1.1 mycroft init.xx = 0; 982 1.19 thorpej ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, init.mbaddr); 983 1.1 mycroft init.nomb = init.nimb = WDS_MBX_SIZE; 984 1.15 mycroft wds_cmd(iot, ioh, (u_char *)&init, sizeof init); 985 1.1 mycroft 986 1.15 mycroft wds_wait(iot, ioh, WDS_STAT, WDSS_INIT, WDSS_INIT); 987 1.1 mycroft 988 1.1 mycroft c = WDSC_DISUNSOL; 989 1.15 mycroft wds_cmd(iot, ioh, &c, sizeof c); 990 1.1 mycroft } 991 1.1 mycroft 992 1.1 mycroft /* 993 1.1 mycroft * Read the board's firmware revision information. 994 1.1 mycroft */ 995 1.1 mycroft void 996 1.70 dsl wds_inquire_setup_information(struct wds_softc *sc) 997 1.1 mycroft { 998 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 999 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 1000 1.1 mycroft struct wds_scb *scb; 1001 1.1 mycroft u_char *j; 1002 1.1 mycroft int s; 1003 1.1 mycroft 1004 1.21 mycroft sc->sc_maxsegs = 1; 1005 1.19 thorpej 1006 1.42 bouyer scb = wds_get_scb(sc); 1007 1.21 mycroft if (scb == 0) 1008 1.21 mycroft panic("wds_inquire_setup_information: no scb available"); 1009 1.19 thorpej 1010 1.1 mycroft scb->xs = NULL; 1011 1.1 mycroft scb->timeout = 40; 1012 1.1 mycroft 1013 1.43 thorpej memset(&scb->cmd, 0, sizeof scb->cmd); 1014 1.1 mycroft scb->cmd.write = 0x80; 1015 1.1 mycroft scb->cmd.opcode = WDSX_GETFIRMREV; 1016 1.1 mycroft 1017 1.1 mycroft /* Will poll card, await result. */ 1018 1.15 mycroft bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN); 1019 1.1 mycroft scb->flags |= SCB_POLLED; 1020 1.1 mycroft 1021 1.1 mycroft s = splbio(); 1022 1.1 mycroft wds_queue_scb(sc, scb); 1023 1.1 mycroft splx(s); 1024 1.1 mycroft 1025 1.1 mycroft if (wds_ipoll(sc, scb, scb->timeout)) 1026 1.1 mycroft goto out; 1027 1.1 mycroft 1028 1.1 mycroft /* Print the version number. */ 1029 1.76 chs printf("%s: version %x.%02x ", device_xname(sc->sc_dev), 1030 1.59 thorpej scb->cmd.targ, scb->cmd.scb[0]); 1031 1.59 thorpej sc->sc_revision = (scb->cmd.targ << 8) | scb->cmd.scb[0]; 1032 1.1 mycroft /* Print out the version string. */ 1033 1.1 mycroft j = 2 + &(scb->cmd.targ); 1034 1.1 mycroft while ((*j >= 32) && (*j < 128)) { 1035 1.12 christos printf("%c", *j); 1036 1.1 mycroft j++; 1037 1.1 mycroft } 1038 1.1 mycroft 1039 1.19 thorpej /* 1040 1.19 thorpej * Determine if we can use scatter/gather. 1041 1.19 thorpej */ 1042 1.19 thorpej if (sc->sc_revision >= 0x800) 1043 1.19 thorpej sc->sc_maxsegs = WDS_NSEG; 1044 1.19 thorpej 1045 1.1 mycroft out: 1046 1.12 christos printf("\n"); 1047 1.61 perry 1048 1.19 thorpej /* 1049 1.19 thorpej * Free up the resources used by this scb. 1050 1.19 thorpej */ 1051 1.21 mycroft wds_free_scb(sc, scb); 1052 1.1 mycroft } 1053 1.1 mycroft 1054 1.1 mycroft void 1055 1.70 dsl wdsminphys(struct buf *bp) 1056 1.1 mycroft { 1057 1.1 mycroft 1058 1.19 thorpej if (bp->b_bcount > WDS_MAXXFER) 1059 1.19 thorpej bp->b_bcount = WDS_MAXXFER; 1060 1.1 mycroft minphys(bp); 1061 1.1 mycroft } 1062 1.1 mycroft 1063 1.1 mycroft /* 1064 1.1 mycroft * Send a SCSI command. 1065 1.1 mycroft */ 1066 1.42 bouyer void 1067 1.77 msaitoh wds_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 1068 1.77 msaitoh void *arg) 1069 1.42 bouyer { 1070 1.18 bouyer struct scsipi_xfer *xs; 1071 1.42 bouyer struct scsipi_periph *periph; 1072 1.76 chs struct wds_softc *sc = device_private(chan->chan_adapter->adapt_dev); 1073 1.19 thorpej bus_dma_tag_t dmat = sc->sc_dmat; 1074 1.1 mycroft struct wds_scb *scb; 1075 1.19 thorpej int error, seg, flags, s; 1076 1.1 mycroft 1077 1.42 bouyer switch (req) { 1078 1.42 bouyer case ADAPTER_REQ_RUN_XFER: 1079 1.42 bouyer xs = arg; 1080 1.42 bouyer periph = xs->xs_periph; 1081 1.42 bouyer 1082 1.42 bouyer if (xs->xs_control & XS_CTL_RESET) { 1083 1.42 bouyer /* XXX Fix me! */ 1084 1.76 chs printf("%s: reset!\n", device_xname(sc->sc_dev)); 1085 1.42 bouyer wds_init(sc, 1); 1086 1.42 bouyer scsipi_done(xs); 1087 1.42 bouyer return; 1088 1.42 bouyer } 1089 1.1 mycroft 1090 1.42 bouyer if (xs->xs_control & XS_CTL_DATA_UIO) { 1091 1.42 bouyer /* XXX Fix me! */ 1092 1.42 bouyer /* 1093 1.42 bouyer * Let's not worry about UIO. There isn't any code 1094 1.42 bouyer * for the non-SG boards anyway! 1095 1.42 bouyer */ 1096 1.77 msaitoh aprint_error_dev(sc->sc_dev, 1097 1.77 msaitoh "UIO is untested and disabled!\n"); 1098 1.25 thorpej xs->error = XS_DRIVER_STUFFUP; 1099 1.42 bouyer scsipi_done(xs); 1100 1.42 bouyer return; 1101 1.25 thorpej } 1102 1.25 thorpej 1103 1.42 bouyer flags = xs->xs_control; 1104 1.25 thorpej 1105 1.42 bouyer /* Get an SCB to use. */ 1106 1.42 bouyer scb = wds_get_scb(sc); 1107 1.42 bouyer #ifdef DIAGNOSTIC 1108 1.25 thorpej /* 1109 1.42 bouyer * This should never happen as we track the resources 1110 1.42 bouyer * in the mid-layer. 1111 1.25 thorpej */ 1112 1.42 bouyer if (scb == NULL) { 1113 1.42 bouyer scsipi_printaddr(periph); 1114 1.42 bouyer printf("unable to allocate scb\n"); 1115 1.42 bouyer panic("wds_scsipi_request"); 1116 1.25 thorpej } 1117 1.42 bouyer #endif 1118 1.25 thorpej 1119 1.42 bouyer scb->xs = xs; 1120 1.42 bouyer scb->timeout = xs->timeout; 1121 1.25 thorpej 1122 1.42 bouyer /* Zero out the command structure. */ 1123 1.59 thorpej if (xs->cmdlen > sizeof(scb->cmd.scb)) { 1124 1.77 msaitoh aprint_error_dev(sc->sc_dev, 1125 1.77 msaitoh "cmdlen %d too large for SCB\n", xs->cmdlen); 1126 1.59 thorpej xs->error = XS_DRIVER_STUFFUP; 1127 1.59 thorpej goto out_bad; 1128 1.59 thorpej } 1129 1.43 thorpej memset(&scb->cmd, 0, sizeof scb->cmd); 1130 1.59 thorpej memcpy(&scb->cmd.scb, xs->cmd, xs->cmdlen); 1131 1.42 bouyer 1132 1.42 bouyer /* Set up some of the command fields. */ 1133 1.42 bouyer scb->cmd.targ = (periph->periph_target << 5) | 1134 1.42 bouyer periph->periph_lun; 1135 1.1 mycroft 1136 1.42 bouyer /* 1137 1.42 bouyer * NOTE: cmd.write may be OK as 0x40 (disable direction 1138 1.42 bouyer * checking) on boards other than the WD-7000V-ASE. Need 1139 1.42 bouyer * this for the ASE: 1140 1.42 bouyer */ 1141 1.42 bouyer scb->cmd.write = (xs->xs_control & XS_CTL_DATA_IN) ? 1142 1.42 bouyer 0x80 : 0x00; 1143 1.1 mycroft 1144 1.42 bouyer if (xs->datalen) { 1145 1.42 bouyer seg = 0; 1146 1.1 mycroft #ifdef TFS 1147 1.42 bouyer if (flags & XS_CTL_DATA_UIO) { 1148 1.42 bouyer error = bus_dmamap_load_uio(dmat, 1149 1.42 bouyer scb->dmamap_xfer, (struct uio *)xs->data, 1150 1.45 thorpej BUS_DMA_NOWAIT | 1151 1.45 thorpej ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ : 1152 1.45 thorpej BUS_DMA_WRITE)); 1153 1.42 bouyer } else 1154 1.1 mycroft #endif /* TFS */ 1155 1.42 bouyer { 1156 1.42 bouyer error = bus_dmamap_load(dmat, 1157 1.42 bouyer scb->dmamap_xfer, xs->data, xs->datalen, 1158 1.45 thorpej NULL, BUS_DMA_NOWAIT | 1159 1.45 thorpej ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ : 1160 1.45 thorpej BUS_DMA_WRITE)); 1161 1.42 bouyer } 1162 1.42 bouyer 1163 1.42 bouyer switch (error) { 1164 1.42 bouyer case 0: 1165 1.42 bouyer break; 1166 1.1 mycroft 1167 1.42 bouyer case ENOMEM: 1168 1.42 bouyer case EAGAIN: 1169 1.42 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1170 1.42 bouyer goto out_bad; 1171 1.42 bouyer 1172 1.42 bouyer default: 1173 1.42 bouyer xs->error = XS_DRIVER_STUFFUP; 1174 1.77 msaitoh aprint_error_dev(sc->sc_dev, 1175 1.77 msaitoh "error %d loading DMA map\n", error); 1176 1.42 bouyer out_bad: 1177 1.42 bouyer wds_free_scb(sc, scb); 1178 1.42 bouyer scsipi_done(xs); 1179 1.42 bouyer return; 1180 1.19 thorpej } 1181 1.1 mycroft 1182 1.42 bouyer bus_dmamap_sync(dmat, scb->dmamap_xfer, 0, 1183 1.42 bouyer scb->dmamap_xfer->dm_mapsize, 1184 1.42 bouyer (flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD : 1185 1.42 bouyer BUS_DMASYNC_PREWRITE); 1186 1.1 mycroft 1187 1.42 bouyer if (sc->sc_maxsegs > 1) { 1188 1.42 bouyer /* 1189 1.42 bouyer * Load the hardware scatter/gather map with the 1190 1.42 bouyer * contents of the DMA map. 1191 1.42 bouyer */ 1192 1.42 bouyer for (seg = 0; 1193 1.42 bouyer seg < scb->dmamap_xfer->dm_nsegs; seg++) { 1194 1.19 thorpej ltophys(scb->dmamap_xfer->dm_segs[seg].ds_addr, 1195 1.42 bouyer scb->scat_gath[seg].seg_addr); 1196 1.19 thorpej ltophys(scb->dmamap_xfer->dm_segs[seg].ds_len, 1197 1.42 bouyer scb->scat_gath[seg].seg_len); 1198 1.42 bouyer } 1199 1.42 bouyer 1200 1.42 bouyer /* 1201 1.42 bouyer * Set up for scatter/gather transfer. 1202 1.42 bouyer */ 1203 1.42 bouyer scb->cmd.opcode = WDSX_SCSISG; 1204 1.42 bouyer ltophys(scb->dmamap_self->dm_segs[0].ds_addr + 1205 1.42 bouyer offsetof(struct wds_scb, scat_gath), 1206 1.42 bouyer scb->cmd.data); 1207 1.42 bouyer ltophys(scb->dmamap_self->dm_nsegs * 1208 1.42 bouyer sizeof(struct wds_scat_gath), scb->cmd.len); 1209 1.42 bouyer } else { 1210 1.42 bouyer /* 1211 1.42 bouyer * This board is an ASC or an ASE, and the 1212 1.42 bouyer * transfer has been mapped contig for us. 1213 1.42 bouyer */ 1214 1.42 bouyer scb->cmd.opcode = WDSX_SCSICMD; 1215 1.42 bouyer ltophys(scb->dmamap_xfer->dm_segs[0].ds_addr, 1216 1.42 bouyer scb->cmd.data); 1217 1.42 bouyer ltophys(scb->dmamap_xfer->dm_segs[0].ds_len, 1218 1.42 bouyer scb->cmd.len); 1219 1.19 thorpej } 1220 1.42 bouyer } else { 1221 1.42 bouyer scb->cmd.opcode = WDSX_SCSICMD; 1222 1.42 bouyer ltophys(0, scb->cmd.data); 1223 1.42 bouyer ltophys(0, scb->cmd.len); 1224 1.42 bouyer } 1225 1.1 mycroft 1226 1.42 bouyer scb->cmd.stat = 0x00; 1227 1.42 bouyer scb->cmd.venderr = 0x00; 1228 1.42 bouyer ltophys(0, scb->cmd.link); 1229 1.42 bouyer 1230 1.42 bouyer /* XXX Do we really want to do this? */ 1231 1.42 bouyer if (flags & XS_CTL_POLL) { 1232 1.42 bouyer /* Will poll card, await result. */ 1233 1.42 bouyer bus_space_write_1(sc->sc_iot, sc->sc_ioh, 1234 1.42 bouyer WDS_HCR, WDSH_DRQEN); 1235 1.42 bouyer scb->flags |= SCB_POLLED; 1236 1.19 thorpej } else { 1237 1.19 thorpej /* 1238 1.42 bouyer * Will send command, let interrupt routine 1239 1.42 bouyer * handle result. 1240 1.1 mycroft */ 1241 1.42 bouyer bus_space_write_1(sc->sc_iot, sc->sc_ioh, WDS_HCR, 1242 1.42 bouyer WDSH_IRQEN | WDSH_DRQEN); 1243 1.1 mycroft } 1244 1.1 mycroft 1245 1.42 bouyer s = splbio(); 1246 1.42 bouyer wds_queue_scb(sc, scb); 1247 1.42 bouyer splx(s); 1248 1.1 mycroft 1249 1.42 bouyer if ((flags & XS_CTL_POLL) == 0) 1250 1.42 bouyer return; 1251 1.1 mycroft 1252 1.42 bouyer if (wds_poll(sc, xs, scb->timeout)) { 1253 1.1 mycroft wds_timeout(scb); 1254 1.42 bouyer if (wds_poll(sc, xs, scb->timeout)) 1255 1.42 bouyer wds_timeout(scb); 1256 1.42 bouyer } 1257 1.42 bouyer return; 1258 1.1 mycroft 1259 1.42 bouyer case ADAPTER_REQ_GROW_RESOURCES: 1260 1.42 bouyer /* XXX Not supported. */ 1261 1.42 bouyer return; 1262 1.1 mycroft 1263 1.42 bouyer case ADAPTER_REQ_SET_XFER_MODE: 1264 1.42 bouyer /* XXX How do we do this? */ 1265 1.42 bouyer return; 1266 1.42 bouyer } 1267 1.1 mycroft } 1268 1.1 mycroft 1269 1.1 mycroft /* 1270 1.1 mycroft * Poll a particular unit, looking for a particular scb 1271 1.1 mycroft */ 1272 1.1 mycroft int 1273 1.70 dsl wds_poll(struct wds_softc *sc, struct scsipi_xfer *xs, int count) 1274 1.1 mycroft { 1275 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 1276 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 1277 1.1 mycroft 1278 1.1 mycroft /* timeouts are in msec, so we loop in 1000 usec cycles */ 1279 1.1 mycroft while (count) { 1280 1.1 mycroft /* 1281 1.1 mycroft * If we had interrupts enabled, would we 1282 1.1 mycroft * have got an interrupt? 1283 1.1 mycroft */ 1284 1.15 mycroft if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) 1285 1.1 mycroft wdsintr(sc); 1286 1.39 thorpej if (xs->xs_status & XS_STS_DONE) 1287 1.1 mycroft return 0; 1288 1.1 mycroft delay(1000); /* only happens in boot so ok */ 1289 1.1 mycroft count--; 1290 1.1 mycroft } 1291 1.1 mycroft return 1; 1292 1.1 mycroft } 1293 1.1 mycroft 1294 1.1 mycroft /* 1295 1.1 mycroft * Poll a particular unit, looking for a particular scb 1296 1.1 mycroft */ 1297 1.1 mycroft int 1298 1.70 dsl wds_ipoll(struct wds_softc *sc, struct wds_scb *scb, int count) 1299 1.1 mycroft { 1300 1.15 mycroft bus_space_tag_t iot = sc->sc_iot; 1301 1.15 mycroft bus_space_handle_t ioh = sc->sc_ioh; 1302 1.1 mycroft 1303 1.1 mycroft /* timeouts are in msec, so we loop in 1000 usec cycles */ 1304 1.1 mycroft while (count) { 1305 1.1 mycroft /* 1306 1.1 mycroft * If we had interrupts enabled, would we 1307 1.1 mycroft * have got an interrupt? 1308 1.1 mycroft */ 1309 1.15 mycroft if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) 1310 1.1 mycroft wdsintr(sc); 1311 1.1 mycroft if (scb->flags & SCB_DONE) 1312 1.1 mycroft return 0; 1313 1.1 mycroft delay(1000); /* only happens in boot so ok */ 1314 1.1 mycroft count--; 1315 1.1 mycroft } 1316 1.1 mycroft return 1; 1317 1.1 mycroft } 1318 1.1 mycroft 1319 1.1 mycroft void 1320 1.70 dsl wds_timeout(void *arg) 1321 1.1 mycroft { 1322 1.1 mycroft struct wds_scb *scb = arg; 1323 1.18 bouyer struct scsipi_xfer *xs = scb->xs; 1324 1.42 bouyer struct scsipi_periph *periph = xs->xs_periph; 1325 1.42 bouyer struct wds_softc *sc = 1326 1.76 chs device_private(periph->periph_channel->chan_adapter->adapt_dev); 1327 1.1 mycroft int s; 1328 1.1 mycroft 1329 1.42 bouyer scsipi_printaddr(periph); 1330 1.12 christos printf("timed out"); 1331 1.1 mycroft 1332 1.1 mycroft s = splbio(); 1333 1.1 mycroft 1334 1.1 mycroft #ifdef WDSDIAG 1335 1.1 mycroft /* 1336 1.1 mycroft * If The scb's mbx is not free, then the board has gone south? 1337 1.1 mycroft */ 1338 1.1 mycroft wds_collect_mbo(sc); 1339 1.1 mycroft if (scb->flags & SCB_SENDING) { 1340 1.76 chs aprint_error_dev(sc->sc_dev, "not taking commands!\n"); 1341 1.1 mycroft Debugger(); 1342 1.1 mycroft } 1343 1.1 mycroft #endif 1344 1.1 mycroft 1345 1.1 mycroft /* 1346 1.1 mycroft * If it has been through before, then 1347 1.1 mycroft * a previous abort has failed, don't 1348 1.1 mycroft * try abort again 1349 1.1 mycroft */ 1350 1.1 mycroft if (scb->flags & SCB_ABORT) { 1351 1.1 mycroft /* abort timed out */ 1352 1.12 christos printf(" AGAIN\n"); 1353 1.1 mycroft /* XXX Must reset! */ 1354 1.1 mycroft } else { 1355 1.1 mycroft /* abort the operation that has timed out */ 1356 1.12 christos printf("\n"); 1357 1.1 mycroft scb->xs->error = XS_TIMEOUT; 1358 1.1 mycroft scb->timeout = WDS_ABORT_TIMEOUT; 1359 1.1 mycroft scb->flags |= SCB_ABORT; 1360 1.1 mycroft wds_queue_scb(sc, scb); 1361 1.1 mycroft } 1362 1.1 mycroft 1363 1.1 mycroft splx(s); 1364 1.1 mycroft } 1365