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