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