1 /* $OpenBSD: wds.c,v 1.41 2014/04/28 10:06:37 jsg Exp $ */ 2 /* $NetBSD: wds.c,v 1.13 1996/11/03 16:20:31 mycroft Exp $ */ 3 4 #undef WDSDIAG 5 #ifdef DDB 6 #define integrate 7 #else 8 #define integrate static inline 9 #endif 10 11 /* 12 * XXX 13 * sense data 14 * aborts 15 * resets 16 */ 17 18 /* 19 * Copyright (c) 1994, 1995 Julian Highfield. All rights reserved. 20 * Portions copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * This product includes software developed by Julian Highfield. 33 * 4. The name of the author may not be used to endorse or promote products 34 * derived from this software without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 37 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 */ 47 48 /* 49 * This driver is for the WD7000 family of SCSI controllers: 50 * the WD7000-ASC, a bus-mastering DMA controller, 51 * the WD7000-FASST2, an -ASC with new firmware and scatter-gather, 52 * and the WD7000-ASE, which was custom manufactured for Apollo 53 * workstations and seems to include an -ASC as well as floppy 54 * and ESDI interfaces. 55 * 56 * Loosely based on Theo Deraadt's unfinished attempt says the NetBSD group 57 * so they decided to delete the copyright that file had on it. 58 */ 59 60 #include <sys/types.h> 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/kernel.h> 64 #include <sys/errno.h> 65 #include <sys/ioctl.h> 66 #include <sys/device.h> 67 #include <sys/malloc.h> 68 #include <sys/buf.h> 69 #include <sys/proc.h> 70 #include <uvm/uvm_extern.h> 71 72 #include <machine/bus.h> 73 #include <machine/intr.h> 74 75 #include <scsi/scsi_all.h> 76 #include <scsi/scsiconf.h> 77 78 #include <dev/isa/isavar.h> 79 #include <dev/isa/isadmavar.h> 80 #include <dev/isa/wdsreg.h> 81 82 #define WDS_MBX_SIZE 16 83 84 #define WDS_SCB_MAX 32 85 #define SCB_HASH_SIZE 32 /* hash table size for phystokv */ 86 #define SCB_HASH_SHIFT 9 87 #define SCB_HASH(x) ((((long)(x))>>SCB_HASH_SHIFT) & (SCB_HASH_SIZE - 1)) 88 89 #define wds_nextmbx(wmb, mbx, mbio) \ 90 if ((wmb) == &(mbx)->mbio[WDS_MBX_SIZE - 1]) \ 91 (wmb) = &(mbx)->mbio[0]; \ 92 else \ 93 (wmb)++; 94 95 struct wds_mbx { 96 struct wds_mbx_out mbo[WDS_MBX_SIZE]; 97 struct wds_mbx_in mbi[WDS_MBX_SIZE]; 98 struct wds_mbx_out *cmbo; /* Collection Mail Box out */ 99 struct wds_mbx_out *tmbo; /* Target Mail Box out */ 100 struct wds_mbx_in *tmbi; /* Target Mail Box in */ 101 }; 102 103 #define KVTOPHYS(x) vtophys((vaddr_t)(x)) 104 105 struct wds_softc { 106 struct device sc_dev; 107 struct isadev sc_id; 108 void *sc_ih; 109 110 bus_space_tag_t sc_iot; /* bus identifier */ 111 bus_space_handle_t sc_ioh; /* io handle */ 112 int sc_irq, sc_drq; 113 114 int sc_revision; 115 116 struct wds_mbx sc_mbx; 117 #define wmbx (&sc->sc_mbx) 118 struct wds_scb *sc_scbhash[SCB_HASH_SIZE]; 119 TAILQ_HEAD(, wds_scb) sc_free_scb, sc_waiting_scb; 120 int sc_numscbs, sc_mbofull; 121 int sc_scsi_dev; 122 struct scsi_link sc_link; /* prototype for subdevs */ 123 124 struct mutex sc_scb_mtx; 125 struct scsi_iopool sc_iopool; 126 }; 127 128 /* Define the bounce buffer length... */ 129 #define BUFLEN (64*1024) 130 /* ..and how many there are. One per device! Non-FASST boards need these. */ 131 #define BUFCNT 8 132 /* The macro for deciding whether the board needs a buffer. */ 133 #define NEEDBUFFER(sc) (sc->sc_revision < 0x800) 134 135 struct wds_buf { 136 u_char data[BUFLEN]; 137 int busy; 138 TAILQ_ENTRY(wds_buf) chain; 139 } wds_buffer[BUFCNT]; 140 141 TAILQ_HEAD(, wds_buf) wds_free_buffer; 142 143 #ifdef WDSDEBUG 144 int wds_debug = WDSDEBUG; 145 #endif 146 147 integrate void wds_wait(bus_space_tag_t, bus_space_handle_t, int, int, int); 148 int wds_cmd(struct wds_softc *, u_char *, int); 149 integrate void wds_finish_scbs(struct wds_softc *); 150 int wdsintr(void *); 151 integrate void wds_reset_scb(struct wds_softc *, struct wds_scb *); 152 void wds_scb_free(void *, void *); 153 void wds_free_buf(struct wds_softc *, struct wds_buf *); 154 integrate void wds_init_scb(struct wds_softc *, struct wds_scb *); 155 void *wds_scb_alloc(void *); 156 struct wds_buf *wds_get_buf(struct wds_softc *, int); 157 struct wds_scb *wds_scb_phys_kv(struct wds_softc *, u_long); 158 void wds_queue_scb(struct wds_softc *, struct wds_scb *); 159 void wds_collect_mbo(struct wds_softc *); 160 void wds_start_scbs(struct wds_softc *); 161 void wds_done(struct wds_softc *, struct wds_scb *, u_char); 162 int wds_find(struct isa_attach_args *, struct wds_softc *); 163 void wds_init(struct wds_softc *); 164 void wds_inquire_setup_information(struct wds_softc *); 165 void wdsminphys(struct buf *, struct scsi_link *); 166 void wds_scsi_cmd(struct scsi_xfer *); 167 void wds_sense(struct wds_softc *, struct wds_scb *); 168 int wds_poll(struct wds_softc *, struct scsi_xfer *, int); 169 int wds_ipoll(struct wds_softc *, struct wds_scb *, int); 170 void wds_timeout(void *); 171 int wdsprint(void *, const char *); 172 173 struct scsi_adapter wds_switch = { 174 wds_scsi_cmd, 175 wdsminphys, 176 0, 177 0, 178 }; 179 180 int wdsprobe(struct device *, void *, void *); 181 void wdsattach(struct device *, struct device *, void *); 182 183 struct cfattach wds_ca = { 184 sizeof(struct wds_softc), wdsprobe, wdsattach 185 }; 186 187 struct cfdriver wds_cd = { 188 NULL, "wds", DV_DULL 189 }; 190 191 #define WDS_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 192 193 integrate void 194 wds_wait(bus_space_tag_t iot, bus_space_handle_t ioh, int port, int mask, 195 int val) 196 { 197 while ((bus_space_read_1(iot, ioh, port) & mask) != val) 198 ; 199 } 200 201 /* 202 * Write a command to the board's I/O ports. 203 */ 204 int 205 wds_cmd(struct wds_softc *sc, u_int8_t *ibuf, int icnt) 206 { 207 bus_space_tag_t iot = sc->sc_iot; 208 bus_space_handle_t ioh = sc->sc_ioh; 209 u_int8_t c; 210 211 wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 212 213 while (icnt--) { 214 bus_space_write_1(iot, ioh, WDS_CMD, *ibuf++); 215 wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 216 c = bus_space_read_1(iot, ioh, WDS_STAT); 217 if (c & WDSS_REJ) 218 return 1; 219 } 220 221 return 0; 222 } 223 224 /* 225 * Check for the presence of a WD7000 SCSI controller. 226 */ 227 int 228 wdsprobe(struct device *parent, void *match, void *aux) 229 { 230 register struct isa_attach_args *ia = aux; 231 bus_space_tag_t iot = ia->ia_iot; 232 bus_space_handle_t ioh; 233 int rv; 234 235 if (bus_space_map(iot, ia->ia_iobase, WDS_IO_PORTS, 0, &ioh)) 236 return (0); 237 238 /* See if there is a unit at this location. */ 239 rv = wds_find(ia, NULL); 240 241 bus_space_unmap(iot, ioh, WDS_IO_PORTS); 242 243 if (rv) { 244 ia->ia_msize = 0; 245 ia->ia_iosize = WDS_IO_PORTS; 246 } 247 248 return (rv); 249 } 250 251 int 252 wdsprint(void *aux, const char *name) 253 { 254 if (name != NULL) 255 printf("%s: scsibus ", name); 256 return UNCONF; 257 } 258 259 /* 260 * Attach all available units. 261 */ 262 void 263 wdsattach(struct device *parent, struct device *self, void *aux) 264 { 265 struct isa_attach_args *ia = aux; 266 struct wds_softc *sc = (void *)self; 267 struct scsibus_attach_args saa; 268 bus_space_tag_t iot = ia->ia_iot; 269 bus_space_handle_t ioh; 270 271 if (bus_space_map(iot, ia->ia_iobase, WDS_IO_PORTS, 0, &ioh)) { 272 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); 273 return; 274 } 275 276 if (!wds_find(ia, sc)) 277 panic("wdsattach: wds_find of %s failed", self->dv_xname); 278 wds_init(sc); 279 280 if (sc->sc_drq != DRQUNK) 281 isadma_cascade(sc->sc_drq); 282 283 TAILQ_INIT(&sc->sc_free_scb); 284 TAILQ_INIT(&sc->sc_waiting_scb); 285 mtx_init(&sc->sc_scb_mtx, IPL_BIO); 286 scsi_iopool_init(&sc->sc_iopool, sc, wds_scb_alloc, wds_scb_free); 287 288 wds_inquire_setup_information(sc); 289 290 /* 291 * fill in the prototype scsi_link. 292 */ 293 sc->sc_link.adapter_softc = sc; 294 sc->sc_link.adapter_target = sc->sc_scsi_dev; 295 sc->sc_link.adapter = &wds_switch; 296 /* XXX */ 297 /* I don't think the -ASE can handle openings > 1. */ 298 /* It gives Vendor Error 26 whenever I try it. */ 299 sc->sc_link.openings = 1; 300 sc->sc_link.pool = &sc->sc_iopool; 301 302 sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE, 303 IPL_BIO, wdsintr, sc, sc->sc_dev.dv_xname); 304 305 bzero(&saa, sizeof(saa)); 306 saa.saa_sc_link = &sc->sc_link; 307 308 /* 309 * ask the adapter what subunits are present 310 */ 311 config_found(self, &saa, wdsprint); 312 } 313 314 integrate void 315 wds_finish_scbs(struct wds_softc *sc) 316 { 317 struct wds_mbx_in *wmbi; 318 struct wds_scb *scb; 319 int i; 320 321 wmbi = wmbx->tmbi; 322 323 if (wmbi->stat == WDS_MBI_FREE) { 324 for (i = 0; i < WDS_MBX_SIZE; i++) { 325 if (wmbi->stat != WDS_MBI_FREE) { 326 printf("%s: mbi not in round-robin order\n", 327 sc->sc_dev.dv_xname); 328 goto AGAIN; 329 } 330 wds_nextmbx(wmbi, wmbx, mbi); 331 } 332 #ifdef WDSDIAGnot 333 printf("%s: mbi interrupt with no full mailboxes\n", 334 sc->sc_dev.dv_xname); 335 #endif 336 return; 337 } 338 339 AGAIN: 340 do { 341 scb = wds_scb_phys_kv(sc, phystol(wmbi->scb_addr)); 342 if (!scb) { 343 printf("%s: bad mbi scb pointer; skipping\n", 344 sc->sc_dev.dv_xname); 345 goto next; 346 } 347 348 #ifdef WDSDEBUG 349 if (wds_debug) { 350 u_int8_t *cp = (u_int8_t *)&scb->cmd.scb; 351 printf("op=%x %x %x %x %x %x\n", 352 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 353 printf("stat %x for mbi addr = 0x%08x, ", 354 wmbi->stat, wmbi); 355 printf("scb addr = 0x%x\n", scb); 356 } 357 #endif /* WDSDEBUG */ 358 359 timeout_del(&scb->xs->stimeout); 360 wds_done(sc, scb, wmbi->stat); 361 362 next: 363 wmbi->stat = WDS_MBI_FREE; 364 wds_nextmbx(wmbi, wmbx, mbi); 365 } while (wmbi->stat != WDS_MBI_FREE); 366 367 wmbx->tmbi = wmbi; 368 } 369 370 /* 371 * Process an interrupt. 372 */ 373 int 374 wdsintr(void *arg) 375 { 376 struct wds_softc *sc = arg; 377 bus_space_tag_t iot = sc->sc_iot; 378 bus_space_handle_t ioh = sc->sc_ioh; 379 u_char c; 380 381 /* Was it really an interrupt from the board? */ 382 if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) == 0) 383 return 0; 384 385 /* Get the interrupt status byte. */ 386 c = bus_space_read_1(iot, ioh, WDS_IRQSTAT) & WDSI_MASK; 387 388 /* Acknowledge (which resets) the interrupt. */ 389 bus_space_write_1(iot, ioh, WDS_IRQACK, 0x00); 390 391 switch (c) { 392 case WDSI_MSVC: 393 wds_finish_scbs(sc); 394 break; 395 396 case WDSI_MFREE: 397 wds_start_scbs(sc); 398 break; 399 400 default: 401 printf("%s: unrecognized interrupt type %02x", 402 sc->sc_dev.dv_xname, c); 403 break; 404 } 405 406 return 1; 407 } 408 409 integrate void 410 wds_reset_scb(struct wds_softc *sc, struct wds_scb *scb) 411 { 412 scb->flags = 0; 413 } 414 415 /* 416 * Free the command structure, the outgoing mailbox and the data buffer. 417 */ 418 void 419 wds_scb_free(void *xsc, void *xscb) 420 { 421 struct wds_softc *sc = xsc; 422 struct wds_scb *scb = xscb; 423 424 if (scb->buf) { 425 wds_free_buf(sc, scb->buf); 426 scb->buf = NULL; 427 } 428 429 wds_reset_scb(sc, scb); 430 mtx_enter(&sc->sc_scb_mtx); 431 TAILQ_INSERT_HEAD(&sc->sc_free_scb, scb, chain); 432 mtx_leave(&sc->sc_scb_mtx); 433 } 434 435 void 436 wds_free_buf(struct wds_softc *sc, struct wds_buf *buf) 437 { 438 int s; 439 440 s = splbio(); 441 442 buf->busy = 0; 443 TAILQ_INSERT_HEAD(&wds_free_buffer, buf, chain); 444 445 /* 446 * If there were none, wake anybody waiting for one to come free, 447 * starting with queued entries. 448 */ 449 if (TAILQ_NEXT(buf, chain) == NULL) 450 wakeup(&wds_free_buffer); 451 452 splx(s); 453 } 454 455 integrate void 456 wds_init_scb(struct wds_softc *sc, struct wds_scb *scb) 457 { 458 int hashnum; 459 460 bzero(scb, sizeof(struct wds_scb)); 461 /* 462 * put in the phystokv hash table 463 * Never gets taken out. 464 */ 465 scb->hashkey = KVTOPHYS(scb); 466 hashnum = SCB_HASH(scb->hashkey); 467 scb->nexthash = sc->sc_scbhash[hashnum]; 468 sc->sc_scbhash[hashnum] = scb; 469 wds_reset_scb(sc, scb); 470 } 471 472 /* 473 * Get a free scb 474 */ 475 void * 476 wds_scb_alloc(void *xsc) 477 { 478 struct wds_softc *sc = xsc; 479 struct wds_scb *scb; 480 481 mtx_enter(&sc->sc_scb_mtx); 482 scb = TAILQ_FIRST(&sc->sc_free_scb); 483 if (scb) { 484 TAILQ_REMOVE(&sc->sc_free_scb, scb, chain); 485 scb->flags |= SCB_ALLOC; 486 } 487 mtx_leave(&sc->sc_scb_mtx); 488 489 return (scb); 490 } 491 492 struct wds_buf * 493 wds_get_buf(struct wds_softc *sc, int flags) 494 { 495 struct wds_buf *buf; 496 int s; 497 498 s = splbio(); 499 500 for (;;) { 501 buf = TAILQ_FIRST(&wds_free_buffer); 502 if (buf) { 503 TAILQ_REMOVE(&wds_free_buffer, buf, chain); 504 break; 505 } 506 if ((flags & SCSI_NOSLEEP) != 0) 507 goto out; 508 tsleep(&wds_free_buffer, PRIBIO, "wdsbuf", 0); 509 } 510 511 buf->busy = 1; 512 513 out: 514 splx(s); 515 return (buf); 516 } 517 518 struct wds_scb * 519 wds_scb_phys_kv(struct wds_softc *sc, u_long scb_phys) 520 { 521 int hashnum = SCB_HASH(scb_phys); 522 struct wds_scb *scb = sc->sc_scbhash[hashnum]; 523 524 while (scb) { 525 if (scb->hashkey == scb_phys) 526 break; 527 /* XXX Check to see if it matches the sense command block. */ 528 if (scb->hashkey == (scb_phys - sizeof(struct wds_cmd))) 529 break; 530 scb = scb->nexthash; 531 } 532 return scb; 533 } 534 535 /* 536 * Queue a SCB to be sent to the controller, and send it if possible. 537 */ 538 void 539 wds_queue_scb(struct wds_softc *sc, struct wds_scb *scb) 540 { 541 TAILQ_INSERT_TAIL(&sc->sc_waiting_scb, scb, chain); 542 wds_start_scbs(sc); 543 } 544 545 /* 546 * Garbage collect mailboxes that are no longer in use. 547 */ 548 void 549 wds_collect_mbo(struct wds_softc *sc) 550 { 551 struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ 552 #ifdef WDSDIAG 553 struct wds_scb *scb; 554 #endif 555 556 wmbo = wmbx->cmbo; 557 558 while (sc->sc_mbofull > 0) { 559 if (wmbo->cmd != WDS_MBO_FREE) 560 break; 561 562 #ifdef WDSDIAG 563 scb = wds_scb_phys_kv(sc, phystol(wmbo->scb_addr)); 564 scb->flags &= ~SCB_SENDING; 565 #endif 566 567 --sc->sc_mbofull; 568 wds_nextmbx(wmbo, wmbx, mbo); 569 } 570 571 wmbx->cmbo = wmbo; 572 } 573 574 /* 575 * Send as many SCBs as we have empty mailboxes for. 576 */ 577 void 578 wds_start_scbs(struct wds_softc *sc) 579 { 580 struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ 581 struct wds_scb *scb; 582 u_char c; 583 584 wmbo = wmbx->tmbo; 585 586 while ((scb = TAILQ_FIRST(&sc->sc_waiting_scb)) != NULL) { 587 if (sc->sc_mbofull >= WDS_MBX_SIZE) { 588 wds_collect_mbo(sc); 589 if (sc->sc_mbofull >= WDS_MBX_SIZE) { 590 c = WDSC_IRQMFREE; 591 wds_cmd(sc, &c, sizeof c); 592 break; 593 } 594 } 595 596 TAILQ_REMOVE(&sc->sc_waiting_scb, scb, chain); 597 #ifdef WDSDIAG 598 scb->flags |= SCB_SENDING; 599 #endif 600 timeout_set(&scb->xs->stimeout, wds_timeout, scb); 601 602 /* Link scb to mbo. */ 603 if (scb->flags & SCB_SENSE) 604 ltophys(KVTOPHYS(&scb->sense), wmbo->scb_addr); 605 else 606 ltophys(KVTOPHYS(&scb->cmd), wmbo->scb_addr); 607 /* XXX What about aborts? */ 608 wmbo->cmd = WDS_MBO_START; 609 610 /* Tell the card to poll immediately. */ 611 c = WDSC_MSTART(wmbo - wmbx->mbo); 612 wds_cmd(sc, &c, sizeof c); 613 614 if ((scb->flags & SCB_POLLED) == 0) 615 timeout_add_msec(&scb->xs->stimeout, scb->timeout); 616 617 ++sc->sc_mbofull; 618 wds_nextmbx(wmbo, wmbx, mbo); 619 } 620 621 wmbx->tmbo = wmbo; 622 } 623 624 /* 625 * Process the result of a SCSI command. 626 */ 627 void 628 wds_done(struct wds_softc *sc, struct wds_scb *scb, u_int8_t stat) 629 { 630 struct scsi_xfer *xs = scb->xs; 631 632 /* XXXXX */ 633 634 /* Don't release the SCB if it was an internal command. */ 635 if (xs == 0) { 636 scb->flags |= SCB_DONE; 637 return; 638 } 639 640 /* Sense handling. */ 641 if (xs->error == XS_SENSE) { 642 bcopy(&scb->sense_data, &xs->sense, sizeof (struct scsi_sense_data)); 643 } else { 644 if (xs->error == XS_NOERROR) { 645 /* If all went well, or an error is acceptable. */ 646 if (stat == WDS_MBI_OK) { 647 /* OK, set the result */ 648 xs->resid = 0; 649 } else { 650 /* Check the mailbox status. */ 651 switch (stat) { 652 case WDS_MBI_OKERR: 653 /* SCSI error recorded in scb, counts as WDS_MBI_OK */ 654 switch (scb->cmd.venderr) { 655 case 0x00: 656 printf("%s: Is this an error?\n", sc->sc_dev.dv_xname); 657 xs->error = XS_DRIVER_STUFFUP; /* Experiment */ 658 break; 659 case 0x01: 660 /*printf("%s: OK, see SCSI error field.\n", sc->sc_dev.dv_xname);*/ 661 if (scb->cmd.stat == SCSI_CHECK) { 662 /* Do sense. */ 663 wds_sense (sc, scb); 664 return; 665 } else if (scb->cmd.stat == SCSI_BUSY) { 666 xs->error = XS_BUSY; 667 } 668 break; 669 case 0x40: 670 /*printf("%s: DMA underrun!\n", sc->sc_dev.dv_xname);*/ 671 /* Hits this if the target returns fewer that datalen bytes (eg my CD-ROM, 672 which returns a short version string, or if DMA is turned off etc. */ 673 xs->resid = 0; 674 break; 675 default: 676 printf("%s: VENDOR ERROR %02x, scsi %02x\n", sc->sc_dev.dv_xname, scb->cmd.venderr, scb->cmd.stat); 677 xs->error = XS_DRIVER_STUFFUP; /* Experiment */ 678 break; 679 } 680 break; 681 case WDS_MBI_ETIME: 682 /* 683 * The documentation isn't clear on 684 * what conditions might generate this, 685 * but selection timeouts are the only 686 * one I can think of. 687 */ 688 xs->error = XS_SELTIMEOUT; 689 break; 690 case WDS_MBI_ERESET: 691 case WDS_MBI_ETARCMD: 692 case WDS_MBI_ERESEL: 693 case WDS_MBI_ESEL: 694 case WDS_MBI_EABORT: 695 case WDS_MBI_ESRESET: 696 case WDS_MBI_EHRESET: 697 xs->error = XS_DRIVER_STUFFUP; 698 break; 699 } 700 } 701 } /* else sense */ 702 703 if (NEEDBUFFER(sc) && xs->datalen) { 704 if (xs->flags & SCSI_DATA_IN) 705 bcopy(scb->buf->data, xs->data, xs->datalen); 706 } 707 } /* XS_NOERROR */ 708 709 scsi_done(xs); 710 } 711 712 int 713 wds_find(struct isa_attach_args *ia, struct wds_softc *sc) 714 { 715 bus_space_tag_t iot = ia->ia_iot; 716 bus_space_handle_t ioh = ia->ia_ioh; 717 u_char c; 718 int i; 719 720 /* 721 * Sending a command causes the CMDRDY bit to clear. 722 */ 723 c = bus_space_read_1(iot, ioh, WDS_STAT); 724 for (i = 0; i < 4; i++) { 725 if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0) 726 goto ready; 727 delay(10); 728 } 729 return (0); 730 731 ready: 732 bus_space_write_1(iot, ioh, WDS_CMD, WDSC_NOOP); 733 if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) 734 return (0); 735 736 bus_space_write_1(iot, ioh, WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET); 737 delay(10000); 738 bus_space_write_1(iot, ioh, WDS_HCR, 0x00); 739 delay(500000); 740 wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY); 741 if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 1) 742 if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 7) 743 printf("%s: failed reset!!! %2x\n", 744 sc ? sc->sc_dev.dv_xname : "wds?", 745 bus_space_read_1(iot, ioh, WDS_IRQSTAT)); 746 747 if ((bus_space_read_1(iot, ioh, WDS_STAT) & (WDSS_RDY)) != WDSS_RDY) { 748 printf("%s: waiting for controller to become ready.", 749 sc ? sc->sc_dev.dv_xname : "wds?"); 750 for (i = 0; i < 20; i++) { 751 if ((bus_space_read_1(iot, ioh, WDS_STAT) & 752 (WDSS_RDY)) == WDSS_RDY) 753 break; 754 printf("."); 755 delay(10000); 756 } 757 if ((bus_space_read_1(iot, ioh, WDS_STAT) & (WDSS_RDY)) != 758 WDSS_RDY) { 759 printf(" failed\n"); 760 return (0); 761 } 762 printf("\n"); 763 } 764 765 if (sc != NULL) { 766 /* XXX Can we do this better? */ 767 /* who are we on the scsi bus? */ 768 sc->sc_scsi_dev = 7; 769 770 sc->sc_iot = iot; 771 sc->sc_ioh = ioh; 772 sc->sc_irq = ia->ia_irq; 773 sc->sc_drq = ia->ia_drq; 774 } 775 776 return (1); 777 } 778 779 /* 780 * Initialise the board and driver. 781 */ 782 void 783 wds_init(struct wds_softc *sc) 784 { 785 bus_space_tag_t iot = sc->sc_iot; 786 bus_space_handle_t ioh = sc->sc_ioh; 787 struct wds_setup init; 788 u_char c; 789 int i; 790 791 /* 792 * Set up initial mail box for round-robin operation. 793 */ 794 for (i = 0; i < WDS_MBX_SIZE; i++) { 795 wmbx->mbo[i].cmd = WDS_MBO_FREE; 796 wmbx->mbi[i].stat = WDS_MBI_FREE; 797 } 798 wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0]; 799 wmbx->tmbi = &wmbx->mbi[0]; 800 sc->sc_mbofull = 0; 801 802 /* Clear the buffers. */ 803 TAILQ_INIT(&wds_free_buffer); 804 for (i = 0; i < BUFCNT; i++) { 805 wds_buffer[i].busy = 0; 806 TAILQ_INSERT_HEAD(&wds_free_buffer, &wds_buffer[i], chain); 807 } 808 809 init.opcode = WDSC_INIT; 810 init.scsi_id = sc->sc_scsi_dev; 811 /* Record scsi id of controller for use in scsi_attach */ 812 sc->sc_scsi_dev = init.scsi_id; 813 init.buson_t = 48; 814 init.busoff_t = 24; 815 init.xx = 0; 816 ltophys(KVTOPHYS(wmbx), init.mbaddr); 817 init.nomb = init.nimb = WDS_MBX_SIZE; 818 wds_cmd(sc, (u_char *)&init, sizeof init); 819 820 wds_wait(iot, ioh, WDS_STAT, WDSS_INIT, WDSS_INIT); 821 822 c = WDSC_DISUNSOL; 823 wds_cmd(sc, &c, sizeof c); 824 825 bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN); 826 } 827 828 /* 829 * Read the board's firmware revision information. 830 */ 831 void 832 wds_inquire_setup_information(struct wds_softc *sc) 833 { 834 struct wds_scb *scb; 835 u_char *j; 836 int s; 837 838 scb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP); 839 if (scb == NULL) { 840 printf("%s: no request slot available in getvers()!\n", 841 sc->sc_dev.dv_xname); 842 return; 843 } 844 scb->xs = NULL; 845 scb->timeout = 40; 846 847 bzero(&scb->cmd, sizeof scb->cmd); 848 scb->cmd.write = 0x80; 849 scb->cmd.opcode = WDSX_GETFIRMREV; 850 851 /* Will poll card, await result. */ 852 bus_space_write_1(sc->sc_iot, sc->sc_ioh, WDS_HCR, WDSH_DRQEN); 853 scb->flags |= SCB_POLLED; 854 855 s = splbio(); 856 wds_queue_scb(sc, scb); 857 splx(s); 858 859 if (wds_ipoll(sc, scb, scb->timeout)) 860 goto out; 861 862 /* Print the version number. */ 863 printf(": version %x.%02x ", scb->cmd.targ, scb->cmd.scb.opcode); 864 sc->sc_revision = (scb->cmd.targ << 8) | scb->cmd.scb.opcode; 865 /* Print out the version string. */ 866 j = 2 + &(scb->cmd.targ); 867 while ((*j >= 32) && (*j < 128)) { 868 printf("%c", *j); 869 j++; 870 } 871 872 out: 873 printf("\n"); 874 scsi_io_put(&sc->sc_iopool, scb); 875 } 876 877 void 878 wdsminphys(struct buf *bp, struct scsi_link *sl) 879 { 880 if (bp->b_bcount > ((WDS_NSEG - 1) << PGSHIFT)) 881 bp->b_bcount = ((WDS_NSEG - 1) << PGSHIFT); 882 minphys(bp); 883 } 884 885 /* 886 * Send a SCSI command. 887 */ 888 void 889 wds_scsi_cmd(struct scsi_xfer *xs) 890 { 891 struct scsi_link *sc_link = xs->sc_link; 892 struct wds_softc *sc = sc_link->adapter_softc; 893 bus_space_tag_t iot = sc->sc_iot; 894 bus_space_handle_t ioh = sc->sc_ioh; 895 struct wds_scb *scb; 896 struct wds_scat_gath *sg; 897 int seg; 898 u_long thiskv, thisphys, nextphys; 899 int bytes_this_seg, bytes_this_page, datalen, flags; 900 int s; 901 902 if (xs->flags & SCSI_RESET) { 903 /* XXX Fix me! */ 904 printf("%s: reset!\n", sc->sc_dev.dv_xname); 905 wds_init(sc); 906 scsi_done(xs); 907 return; 908 } 909 910 flags = xs->flags; 911 scb = xs->io; 912 scb->xs = xs; 913 scb->timeout = xs->timeout; 914 915 /* Zero out the command structure. */ 916 bzero(&scb->cmd, sizeof scb->cmd); 917 bcopy(xs->cmd, &scb->cmd.scb, xs->cmdlen < 12 ? xs->cmdlen : 12); 918 919 /* Set up some of the command fields. */ 920 scb->cmd.targ = (xs->sc_link->target << 5) | xs->sc_link->lun; 921 922 /* NOTE: cmd.write may be OK as 0x40 (disable direction checking) 923 * on boards other than the WD-7000V-ASE. Need this for the ASE: 924 */ 925 scb->cmd.write = (xs->flags & SCSI_DATA_IN) ? 0x80 : 0x00; 926 927 if (!NEEDBUFFER(sc) && xs->datalen) { 928 sg = scb->scat_gath; 929 seg = 0; 930 931 /* 932 * Set up the scatter-gather block. 933 */ 934 SC_DEBUG(sc_link, SDEV_DB4, 935 ("%d @0x%x:- ", xs->datalen, xs->data)); 936 937 datalen = xs->datalen; 938 thiskv = (int)xs->data; 939 thisphys = KVTOPHYS(xs->data); 940 941 while (datalen && seg < WDS_NSEG) { 942 bytes_this_seg = 0; 943 944 /* put in the base address */ 945 ltophys(thisphys, sg->seg_addr); 946 947 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); 948 949 /* do it at least once */ 950 nextphys = thisphys; 951 while (datalen && thisphys == nextphys) { 952 /* 953 * This page is contiguous (physically) 954 * with the last, just extend the 955 * length 956 */ 957 /* check it fits on the ISA bus */ 958 if (thisphys > 0xFFFFFF) { 959 printf("%s: DMA beyond" 960 " end of ISA\n", 961 sc->sc_dev.dv_xname); 962 goto bad; 963 } 964 /* how far to the end of the page */ 965 nextphys = (thisphys & ~PGOFSET) + NBPG; 966 bytes_this_page = nextphys - thisphys; 967 /**** or the data ****/ 968 bytes_this_page = min(bytes_this_page, 969 datalen); 970 bytes_this_seg += bytes_this_page; 971 datalen -= bytes_this_page; 972 973 /* get more ready for the next page */ 974 thiskv = (thiskv & ~PGOFSET) + NBPG; 975 if (datalen) 976 thisphys = KVTOPHYS(thiskv); 977 } 978 /* 979 * next page isn't contiguous, finish the seg 980 */ 981 SC_DEBUGN(sc_link, SDEV_DB4, 982 ("(0x%x)", bytes_this_seg)); 983 ltophys(bytes_this_seg, sg->seg_len); 984 sg++; 985 seg++; 986 } 987 988 SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); 989 if (datalen) { 990 /* 991 * there's still data, must have run out of segs! 992 */ 993 printf("%s: wds_scsi_cmd, more than %d dma segs\n", 994 sc->sc_dev.dv_xname, WDS_NSEG); 995 goto bad; 996 } 997 scb->cmd.opcode = WDSX_SCSISG; 998 ltophys(KVTOPHYS(scb->scat_gath), scb->cmd.data); 999 ltophys(seg * sizeof(struct wds_scat_gath), scb->cmd.len); 1000 } else if (xs->datalen > 0) { 1001 /* The board is an ASC or ASE. Do not use scatter/gather. */ 1002 if (xs->datalen > BUFLEN) { 1003 printf("%s: wds_scsi_cmd, I/O too large for bounce buffer\n", 1004 sc->sc_dev.dv_xname); 1005 goto bad; 1006 } 1007 if (xs->flags & SCSI_DATA_OUT) 1008 bcopy(xs->data, scb->buf->data, xs->datalen); 1009 else 1010 bzero(scb->buf->data, xs->datalen); 1011 scb->cmd.opcode = WDSX_SCSICMD; 1012 ltophys(KVTOPHYS(scb->buf->data), scb->cmd.data); 1013 ltophys(xs->datalen, scb->cmd.len); 1014 } else { 1015 scb->cmd.opcode = WDSX_SCSICMD; 1016 ltophys(0, scb->cmd.data); 1017 ltophys(0, scb->cmd.len); 1018 } 1019 1020 scb->cmd.stat = 0x00; 1021 scb->cmd.venderr = 0x00; 1022 ltophys(0, scb->cmd.link); 1023 1024 /* XXX Do we really want to do this? */ 1025 if (flags & SCSI_POLL) { 1026 /* Will poll card, await result. */ 1027 bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN); 1028 scb->flags |= SCB_POLLED; 1029 } else { 1030 /* Will send command, let interrupt routine handle result. */ 1031 bus_space_write_1(iot, ioh, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 1032 } 1033 1034 s = splbio(); 1035 wds_queue_scb(sc, scb); 1036 1037 splx(s); 1038 1039 if ((flags & SCSI_POLL) == 0) 1040 return; 1041 1042 if (wds_poll(sc, xs, scb->timeout)) { 1043 wds_timeout(scb); 1044 if (wds_poll(sc, xs, scb->timeout)) 1045 wds_timeout(scb); 1046 } 1047 return; 1048 1049 bad: 1050 xs->error = XS_DRIVER_STUFFUP; 1051 } 1052 1053 /* 1054 * Send a sense request. 1055 */ 1056 void 1057 wds_sense(struct wds_softc *sc, struct wds_scb *scb) 1058 { 1059 struct scsi_xfer *xs = scb->xs; 1060 struct scsi_sense *ss = (void *)&scb->sense.scb; 1061 int s; 1062 1063 /* XXXXX */ 1064 1065 /* Send sense request SCSI command. */ 1066 xs->error = XS_SENSE; 1067 scb->flags |= SCB_SENSE; 1068 1069 /* First, save the return values */ 1070 if (NEEDBUFFER(sc) && xs->datalen) { 1071 if (xs->flags & SCSI_DATA_IN) 1072 bcopy(scb->buf->data, xs->data, xs->datalen); 1073 } 1074 1075 /* Next, setup a request sense command block */ 1076 bzero(ss, sizeof(*ss)); 1077 ss->opcode = REQUEST_SENSE; 1078 ss->byte2 = xs->sc_link->lun << 5; 1079 ss->length = sizeof(struct scsi_sense_data); 1080 1081 /* Set up some of the command fields. */ 1082 scb->sense.targ = scb->cmd.targ; 1083 scb->sense.write = 0x80; 1084 scb->sense.opcode = WDSX_SCSICMD; 1085 ltophys(KVTOPHYS(&scb->sense_data), scb->sense.data); 1086 ltophys(sizeof(struct scsi_sense_data), scb->sense.len); 1087 1088 s = splbio(); 1089 wds_queue_scb(sc, scb); 1090 splx(s); 1091 1092 /* 1093 * There's no reason for us to poll here. There are two cases: 1094 * 1) If it's a polling operation, then we're called from the interrupt 1095 * handler, and we return and continue polling. 1096 * 2) If it's an interrupt-driven operation, then it gets completed 1097 * later on when the REQUEST SENSE finishes. 1098 */ 1099 } 1100 1101 /* 1102 * Poll a particular unit, looking for a particular scb 1103 */ 1104 int 1105 wds_poll(struct wds_softc *sc, struct scsi_xfer *xs, int count) 1106 { 1107 bus_space_tag_t iot = sc->sc_iot; 1108 bus_space_handle_t ioh = sc->sc_ioh; 1109 int s; 1110 1111 /* timeouts are in msec, so we loop in 1000 usec cycles */ 1112 while (count) { 1113 /* 1114 * If we had interrupts enabled, would we 1115 * have got an interrupt? 1116 */ 1117 if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) { 1118 s = splbio(); 1119 wdsintr(sc); 1120 splx(s); 1121 } 1122 if (xs->flags & ITSDONE) 1123 return 0; 1124 delay(1000); /* only happens in boot so ok */ 1125 count--; 1126 } 1127 return 1; 1128 } 1129 1130 /* 1131 * Poll a particular unit, looking for a particular scb 1132 */ 1133 int 1134 wds_ipoll(struct wds_softc *sc, struct wds_scb *scb, int count) 1135 { 1136 bus_space_tag_t iot = sc->sc_iot; 1137 bus_space_handle_t ioh = sc->sc_ioh; 1138 int s; 1139 1140 /* timeouts are in msec, so we loop in 1000 usec cycles */ 1141 while (count) { 1142 /* 1143 * If we had interrupts enabled, would we 1144 * have got an interrupt? 1145 */ 1146 if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) { 1147 s = splbio(); 1148 wdsintr(sc); 1149 splx(s); 1150 } 1151 if (scb->flags & SCB_DONE) 1152 return 0; 1153 delay(1000); /* only happens in boot so ok */ 1154 count--; 1155 } 1156 return 1; 1157 } 1158 1159 void 1160 wds_timeout(void *arg) 1161 { 1162 struct wds_scb *scb = arg; 1163 struct scsi_xfer *xs; 1164 struct scsi_link *sc_link; 1165 struct wds_softc *sc; 1166 int s; 1167 1168 s = splbio(); 1169 xs = scb->xs; 1170 sc_link = xs->sc_link; 1171 sc = sc_link->adapter_softc; 1172 1173 sc_print_addr(sc_link); 1174 printf("timed out"); 1175 1176 #ifdef WDSDIAG 1177 /* 1178 * If The scb's mbx is not free, then the board has gone south? 1179 */ 1180 wds_collect_mbo(sc); 1181 if (scb->flags & SCB_SENDING) 1182 panic("%s: not taking commands!", sc->sc_dev.dv_xname); 1183 #endif 1184 1185 /* 1186 * If it has been through before, then 1187 * a previous abort has failed, don't 1188 * try abort again 1189 */ 1190 if (scb->flags & SCB_ABORT) { 1191 /* abort timed out */ 1192 printf(" AGAIN\n"); 1193 /* XXX Must reset! */ 1194 } else { 1195 /* abort the operation that has timed out */ 1196 printf("\n"); 1197 scb->xs->error = XS_TIMEOUT; 1198 scb->timeout = WDS_ABORT_TIMEOUT; 1199 scb->flags |= SCB_ABORT; 1200 wds_queue_scb(sc, scb); 1201 } 1202 1203 splx(s); 1204 } 1205