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