Annotation of sys/dev/ic/uha.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uha.c,v 1.9 2006/11/28 23:59:45 dlg Exp $ */
! 2: /* $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */
! 3:
! 4: #undef UHADEBUG
! 5: #ifdef DDB
! 6: #define integrate
! 7: #else
! 8: #define integrate static inline
! 9: #endif
! 10:
! 11: /*
! 12: * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
! 13: *
! 14: * Redistribution and use in source and binary forms, with or without
! 15: * modification, are permitted provided that the following conditions
! 16: * are met:
! 17: * 1. Redistributions of source code must retain the above copyright
! 18: * notice, this list of conditions and the following disclaimer.
! 19: * 2. Redistributions in binary form must reproduce the above copyright
! 20: * notice, this list of conditions and the following disclaimer in the
! 21: * documentation and/or other materials provided with the distribution.
! 22: * 3. All advertising materials mentioning features or use of this software
! 23: * must display the following acknowledgement:
! 24: * This product includes software developed by Charles M. Hannum.
! 25: * 4. The name of the author may not be used to endorse or promote products
! 26: * derived from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 29: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 30: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 31: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 32: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 33: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 34: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 35: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 36: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 37: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
! 42: * Slight fixes to timeouts to run with the 34F
! 43: * Thanks to Julian Elischer for advice and help with this port.
! 44: *
! 45: * Originally written by Julian Elischer (julian@tfs.com)
! 46: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 47: *
! 48: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 49: * Mellon University, makes this software available to CMU to distribute
! 50: * or use in any manner that they see fit as long as this message is kept with
! 51: * the software. For this reason TFS also grants any other persons or
! 52: * organisations permission to use or modify this software.
! 53: *
! 54: * TFS supplies this software to be publicly redistributed
! 55: * on the understanding that TFS is not responsible for the correct
! 56: * functioning of this software in any circumstances.
! 57: *
! 58: * commenced: Sun Sep 27 18:14:01 PDT 1992
! 59: * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993
! 60: */
! 61:
! 62: #include <sys/types.h>
! 63: #include <sys/param.h>
! 64: #include <sys/systm.h>
! 65: #include <sys/kernel.h>
! 66: #include <sys/errno.h>
! 67: #include <sys/ioctl.h>
! 68: #include <sys/device.h>
! 69: #include <sys/malloc.h>
! 70: #include <sys/buf.h>
! 71: #include <sys/proc.h>
! 72: #include <sys/user.h>
! 73:
! 74: #include <machine/bus.h>
! 75: #include <machine/intr.h>
! 76:
! 77: #include <scsi/scsi_all.h>
! 78: #include <scsi/scsiconf.h>
! 79:
! 80: #include <dev/ic/uhareg.h>
! 81: #include <dev/ic/uhavar.h>
! 82:
! 83: #ifndef DDB
! 84: #define Debugger() panic("should call debugger here (ultra14f.c)")
! 85: #endif /* ! DDB */
! 86:
! 87: #define KVTOPHYS(x) vtophys((vaddr_t)x)
! 88:
! 89: integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *);
! 90: void uha_free_mscp(struct uha_softc *, struct uha_mscp *);
! 91: integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *);
! 92: struct uha_mscp *uha_get_mscp(struct uha_softc *, int);
! 93: void uhaminphys(struct buf *);
! 94: int uha_scsi_cmd(struct scsi_xfer *);
! 95:
! 96: struct scsi_adapter uha_switch = {
! 97: uha_scsi_cmd,
! 98: uhaminphys,
! 99: 0,
! 100: 0,
! 101: };
! 102:
! 103: /* the below structure is so we have a default dev struct for out link struct */
! 104: struct scsi_device uha_dev = {
! 105: NULL, /* Use default error handler */
! 106: NULL, /* have a queue, served by this */
! 107: NULL, /* have no async handler */
! 108: NULL, /* Use default 'done' routine */
! 109: };
! 110:
! 111: struct cfdriver uha_cd = {
! 112: NULL, "uha", DV_DULL
! 113: };
! 114:
! 115: #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
! 116:
! 117: #ifdef __OpenBSD__
! 118: int uhaprint(void *, const char *);
! 119:
! 120: int
! 121: uhaprint(aux, name)
! 122: void *aux;
! 123: const char *name;
! 124: {
! 125:
! 126: if (name != NULL)
! 127: printf("%s: scsibus ", name);
! 128: return UNCONF;
! 129: }
! 130: #endif
! 131:
! 132: /*
! 133: * Attach all the sub-devices we can find
! 134: */
! 135: void
! 136: uha_attach(sc)
! 137: struct uha_softc *sc;
! 138: {
! 139: struct scsibus_attach_args saa;
! 140:
! 141: (sc->init)(sc);
! 142: TAILQ_INIT(&sc->sc_free_mscp);
! 143:
! 144: /*
! 145: * fill in the prototype scsi_link.
! 146: */
! 147: sc->sc_link.adapter_softc = sc;
! 148: sc->sc_link.adapter_target = sc->sc_scsi_dev;
! 149: sc->sc_link.adapter = &uha_switch;
! 150: sc->sc_link.device = &uha_dev;
! 151: sc->sc_link.openings = 2;
! 152:
! 153: bzero(&saa, sizeof(saa));
! 154: saa.saa_sc_link = &sc->sc_link;
! 155:
! 156: /*
! 157: * ask the adapter what subunits are present
! 158: */
! 159: config_found(&sc->sc_dev, &saa, uhaprint);
! 160: }
! 161:
! 162: integrate void
! 163: uha_reset_mscp(sc, mscp)
! 164: struct uha_softc *sc;
! 165: struct uha_mscp *mscp;
! 166: {
! 167:
! 168: mscp->flags = 0;
! 169: }
! 170:
! 171: /*
! 172: * A mscp (and hence a mbx-out) is put onto the free list.
! 173: */
! 174: void
! 175: uha_free_mscp(sc, mscp)
! 176: struct uha_softc *sc;
! 177: struct uha_mscp *mscp;
! 178: {
! 179: int s;
! 180:
! 181: s = splbio();
! 182:
! 183: uha_reset_mscp(sc, mscp);
! 184: TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
! 185:
! 186: /*
! 187: * If there were none, wake anybody waiting for one to come free,
! 188: * starting with queued entries.
! 189: */
! 190: if (TAILQ_NEXT(mscp, chain) == NULL)
! 191: wakeup(&sc->sc_free_mscp);
! 192:
! 193: splx(s);
! 194: }
! 195:
! 196: integrate void
! 197: uha_init_mscp(sc, mscp)
! 198: struct uha_softc *sc;
! 199: struct uha_mscp *mscp;
! 200: {
! 201: int hashnum;
! 202:
! 203: bzero(mscp, sizeof(struct uha_mscp));
! 204: /*
! 205: * put in the phystokv hash table
! 206: * Never gets taken out.
! 207: */
! 208: mscp->hashkey = KVTOPHYS(mscp);
! 209: hashnum = MSCP_HASH(mscp->hashkey);
! 210: mscp->nexthash = sc->sc_mscphash[hashnum];
! 211: sc->sc_mscphash[hashnum] = mscp;
! 212: uha_reset_mscp(sc, mscp);
! 213: }
! 214:
! 215: /*
! 216: * Get a free mscp
! 217: *
! 218: * If there are none, see if we can allocate a new one. If so, put it in the
! 219: * hash table too otherwise either return an error or sleep.
! 220: */
! 221: struct uha_mscp *
! 222: uha_get_mscp(sc, flags)
! 223: struct uha_softc *sc;
! 224: int flags;
! 225: {
! 226: struct uha_mscp *mscp;
! 227: int s;
! 228:
! 229: s = splbio();
! 230:
! 231: /*
! 232: * If we can and have to, sleep waiting for one to come free
! 233: * but only if we can't allocate a new one
! 234: */
! 235: for (;;) {
! 236: mscp = TAILQ_FIRST(&sc->sc_free_mscp);
! 237: if (mscp) {
! 238: TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
! 239: break;
! 240: }
! 241: if (sc->sc_nummscps < UHA_MSCP_MAX) {
! 242: mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp),
! 243: M_TEMP, M_NOWAIT);
! 244: if (!mscp) {
! 245: printf("%s: can't malloc mscp\n",
! 246: sc->sc_dev.dv_xname);
! 247: goto out;
! 248: }
! 249: uha_init_mscp(sc, mscp);
! 250: sc->sc_nummscps++;
! 251: break;
! 252: }
! 253: if ((flags & SCSI_NOSLEEP) != 0)
! 254: goto out;
! 255: tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
! 256: }
! 257:
! 258: mscp->flags |= MSCP_ALLOC;
! 259:
! 260: out:
! 261: splx(s);
! 262: return (mscp);
! 263: }
! 264:
! 265: /*
! 266: * given a physical address, find the mscp that it corresponds to.
! 267: */
! 268: struct uha_mscp *
! 269: uha_mscp_phys_kv(sc, mscp_phys)
! 270: struct uha_softc *sc;
! 271: u_long mscp_phys;
! 272: {
! 273: int hashnum = MSCP_HASH(mscp_phys);
! 274: struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
! 275:
! 276: while (mscp) {
! 277: if (mscp->hashkey == mscp_phys)
! 278: break;
! 279: mscp = mscp->nexthash;
! 280: }
! 281: return (mscp);
! 282: }
! 283:
! 284: /*
! 285: * We have a mscp which has been processed by the adaptor, now we look to see
! 286: * how the operation went.
! 287: */
! 288: void
! 289: uha_done(sc, mscp)
! 290: struct uha_softc *sc;
! 291: struct uha_mscp *mscp;
! 292: {
! 293: struct scsi_sense_data *s1, *s2;
! 294: struct scsi_xfer *xs = mscp->xs;
! 295:
! 296: SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
! 297: /*
! 298: * Otherwise, put the results of the operation
! 299: * into the xfer and call whoever started it
! 300: */
! 301: if ((mscp->flags & MSCP_ALLOC) == 0) {
! 302: printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
! 303: Debugger();
! 304: return;
! 305: }
! 306: if (xs->error == XS_NOERROR) {
! 307: if (mscp->host_stat != UHA_NO_ERR) {
! 308: switch (mscp->host_stat) {
! 309: case UHA_SBUS_TIMEOUT: /* No response */
! 310: xs->error = XS_SELTIMEOUT;
! 311: break;
! 312: default: /* Other scsi protocol messes */
! 313: printf("%s: host_stat %x\n",
! 314: sc->sc_dev.dv_xname, mscp->host_stat);
! 315: xs->error = XS_DRIVER_STUFFUP;
! 316: }
! 317: } else if (mscp->target_stat != SCSI_OK) {
! 318: switch (mscp->target_stat) {
! 319: case SCSI_CHECK:
! 320: s1 = &mscp->mscp_sense;
! 321: s2 = &xs->sense;
! 322: *s2 = *s1;
! 323: xs->error = XS_SENSE;
! 324: break;
! 325: case SCSI_BUSY:
! 326: xs->error = XS_BUSY;
! 327: break;
! 328: default:
! 329: printf("%s: target_stat %x\n",
! 330: sc->sc_dev.dv_xname, mscp->target_stat);
! 331: xs->error = XS_DRIVER_STUFFUP;
! 332: }
! 333: } else
! 334: xs->resid = 0;
! 335: }
! 336: uha_free_mscp(sc, mscp);
! 337: xs->flags |= ITSDONE;
! 338: scsi_done(xs);
! 339: }
! 340:
! 341: void
! 342: uhaminphys(bp)
! 343: struct buf *bp;
! 344: {
! 345:
! 346: if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT))
! 347: bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT);
! 348: minphys(bp);
! 349: }
! 350:
! 351: /*
! 352: * start a scsi operation given the command and the data address. Also
! 353: * needs the unit, target and lu.
! 354: */
! 355: int
! 356: uha_scsi_cmd(xs)
! 357: struct scsi_xfer *xs;
! 358: {
! 359: struct scsi_link *sc_link = xs->sc_link;
! 360: struct uha_softc *sc = sc_link->adapter_softc;
! 361: struct uha_mscp *mscp;
! 362: struct uha_dma_seg *sg;
! 363: int seg; /* scatter gather seg being worked on */
! 364: u_long thiskv, thisphys, nextphys;
! 365: int bytes_this_seg, bytes_this_page, datalen, flags;
! 366: int s;
! 367:
! 368: SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
! 369: /*
! 370: * get a mscp (mbox-out) to use. If the transfer
! 371: * is from a buf (possibly from interrupt time)
! 372: * then we can't allow it to sleep
! 373: */
! 374: flags = xs->flags;
! 375: if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
! 376: return (TRY_AGAIN_LATER);
! 377: }
! 378: mscp->xs = xs;
! 379: mscp->timeout = xs->timeout;
! 380: timeout_set(&xs->stimeout, uha_timeout, xs);
! 381:
! 382: /*
! 383: * Put all the arguments for the xfer in the mscp
! 384: */
! 385: if (flags & SCSI_RESET) {
! 386: mscp->opcode = UHA_SDR;
! 387: mscp->ca = 0x01;
! 388: } else {
! 389: mscp->opcode = UHA_TSP;
! 390: /* XXX Not for tapes. */
! 391: mscp->ca = 0x01;
! 392: bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
! 393: }
! 394: mscp->xdir = UHA_SDET;
! 395: mscp->dcn = 0x00;
! 396: mscp->chan = 0x00;
! 397: mscp->target = sc_link->target;
! 398: mscp->lun = sc_link->lun;
! 399: mscp->scsi_cmd_length = xs->cmdlen;
! 400: mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
! 401: mscp->req_sense_length = sizeof(mscp->mscp_sense);
! 402: mscp->host_stat = 0x00;
! 403: mscp->target_stat = 0x00;
! 404:
! 405: if (xs->datalen) {
! 406: sg = mscp->uha_dma;
! 407: seg = 0;
! 408: #ifdef TFS
! 409: if (flags & SCSI_DATA_UIO) {
! 410: struct iovec *iovp;
! 411: iovp = ((struct uio *) xs->data)->uio_iov;
! 412: datalen = ((struct uio *) xs->data)->uio_iovcnt;
! 413: xs->datalen = 0;
! 414: while (datalen && seg < UHA_NSEG) {
! 415: sg->seg_addr = (physaddr)iovp->iov_base;
! 416: sg->seg_len = iovp->iov_len;
! 417: xs->datalen += iovp->iov_len;
! 418: SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
! 419: iovp->iov_len, iovp->iov_base));
! 420: sg++;
! 421: iovp++;
! 422: seg++;
! 423: datalen--;
! 424: }
! 425: } else
! 426: #endif /*TFS */
! 427: {
! 428: /*
! 429: * Set up the scatter gather block
! 430: */
! 431: SC_DEBUG(sc_link, SDEV_DB4,
! 432: ("%d @0x%x:- ", xs->datalen, xs->data));
! 433: datalen = xs->datalen;
! 434: thiskv = (int) xs->data;
! 435: thisphys = KVTOPHYS(thiskv);
! 436:
! 437: while (datalen && seg < UHA_NSEG) {
! 438: bytes_this_seg = 0;
! 439:
! 440: /* put in the base address */
! 441: sg->seg_addr = thisphys;
! 442:
! 443: SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
! 444:
! 445: /* do it at least once */
! 446: nextphys = thisphys;
! 447: while (datalen && thisphys == nextphys) {
! 448: /*
! 449: * This page is contiguous (physically)
! 450: * with the last, just extend the
! 451: * length
! 452: */
! 453: /* how far to the end of the page */
! 454: nextphys = (thisphys & ~PGOFSET) + NBPG;
! 455: bytes_this_page = nextphys - thisphys;
! 456: /**** or the data ****/
! 457: bytes_this_page = min(bytes_this_page,
! 458: datalen);
! 459: bytes_this_seg += bytes_this_page;
! 460: datalen -= bytes_this_page;
! 461:
! 462: /* get more ready for the next page */
! 463: thiskv = (thiskv & ~PGOFSET) + NBPG;
! 464: if (datalen)
! 465: thisphys = KVTOPHYS(thiskv);
! 466: }
! 467: /*
! 468: * next page isn't contiguous, finish the seg
! 469: */
! 470: SC_DEBUGN(sc_link, SDEV_DB4,
! 471: ("(0x%x)", bytes_this_seg));
! 472: sg->seg_len = bytes_this_seg;
! 473: sg++;
! 474: seg++;
! 475: }
! 476: }
! 477: /* end of iov/kv decision */
! 478: SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
! 479: if (datalen) {
! 480: /*
! 481: * there's still data, must have run out of segs!
! 482: */
! 483: printf("%s: uha_scsi_cmd, more than %d dma segs\n",
! 484: sc->sc_dev.dv_xname, UHA_NSEG);
! 485: goto bad;
! 486: }
! 487: mscp->data_addr = KVTOPHYS(mscp->uha_dma);
! 488: mscp->data_length = xs->datalen;
! 489: mscp->sgth = 0x01;
! 490: mscp->sg_num = seg;
! 491: } else { /* No data xfer, use non S/G values */
! 492: mscp->data_addr = (physaddr)0;
! 493: mscp->data_length = 0;
! 494: mscp->sgth = 0x00;
! 495: mscp->sg_num = 0;
! 496: }
! 497: mscp->link_id = 0;
! 498: mscp->link_addr = (physaddr)0;
! 499:
! 500: s = splbio();
! 501: (sc->start_mbox)(sc, mscp);
! 502: splx(s);
! 503:
! 504: /*
! 505: * Usually return SUCCESSFULLY QUEUED
! 506: */
! 507: if ((flags & SCSI_POLL) == 0)
! 508: return (SUCCESSFULLY_QUEUED);
! 509:
! 510: /*
! 511: * If we can't use interrupts, poll on completion
! 512: */
! 513: if ((sc->poll)(sc, xs, mscp->timeout)) {
! 514: uha_timeout(mscp);
! 515: if ((sc->poll)(sc, xs, mscp->timeout))
! 516: uha_timeout(mscp);
! 517: }
! 518: return (COMPLETE);
! 519:
! 520: bad:
! 521: xs->error = XS_DRIVER_STUFFUP;
! 522: uha_free_mscp(sc, mscp);
! 523: return (COMPLETE);
! 524: }
! 525:
! 526: void
! 527: uha_timeout(arg)
! 528: void *arg;
! 529: {
! 530: struct uha_mscp *mscp = arg;
! 531: struct scsi_xfer *xs = mscp->xs;
! 532: struct scsi_link *sc_link = xs->sc_link;
! 533: struct uha_softc *sc = sc_link->adapter_softc;
! 534: int s;
! 535:
! 536: sc_print_addr(sc_link);
! 537: printf("timed out");
! 538:
! 539: s = splbio();
! 540:
! 541: if (mscp->flags & MSCP_ABORT) {
! 542: /* abort timed out */
! 543: printf(" AGAIN\n");
! 544: /* XXX Must reset! */
! 545: } else {
! 546: /* abort the operation that has timed out */
! 547: printf("\n");
! 548: mscp->xs->error = XS_TIMEOUT;
! 549: mscp->timeout = UHA_ABORT_TIMEOUT;
! 550: mscp->flags |= MSCP_ABORT;
! 551: (sc->start_mbox)(sc, mscp);
! 552: }
! 553:
! 554: splx(s);
! 555: }
CVSweb