Annotation of sys/dev/ic/adv.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: adv.c,v 1.17 2006/11/29 01:00:47 grange Exp $ */
! 2: /* $NetBSD: adv.c,v 1.6 1998/10/28 20:39:45 dante Exp $ */
! 3:
! 4: /*
! 5: * Generic driver for the Advanced Systems Inc. Narrow SCSI controllers
! 6: *
! 7: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 8: * All rights reserved.
! 9: *
! 10: * Author: Baldassare Dante Profeta <dante@mclink.it>
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/errno.h>
! 46: #include <sys/ioctl.h>
! 47: #include <sys/device.h>
! 48: #include <sys/malloc.h>
! 49: #include <sys/buf.h>
! 50: #include <sys/proc.h>
! 51: #include <sys/user.h>
! 52:
! 53: #include <machine/bus.h>
! 54: #include <machine/intr.h>
! 55:
! 56: #include <scsi/scsi_all.h>
! 57: #include <scsi/scsiconf.h>
! 58:
! 59: #include <dev/ic/adv.h>
! 60: #include <dev/ic/advlib.h>
! 61:
! 62: #ifndef DDB
! 63: #define Debugger() panic("should call debugger here (adv.c)")
! 64: #endif /* ! DDB */
! 65:
! 66:
! 67: /* #define ASC_DEBUG */
! 68:
! 69: /******************************************************************************/
! 70:
! 71:
! 72: static void adv_enqueue(ASC_SOFTC *, struct scsi_xfer *, int);
! 73: static struct scsi_xfer *adv_dequeue(ASC_SOFTC *);
! 74:
! 75: static int adv_alloc_ccbs(ASC_SOFTC *);
! 76: static int adv_create_ccbs(ASC_SOFTC *, ADV_CCB *, int);
! 77: static void adv_free_ccb(ASC_SOFTC *, ADV_CCB *);
! 78: static void adv_reset_ccb(ADV_CCB *);
! 79: static int adv_init_ccb(ASC_SOFTC *, ADV_CCB *);
! 80: static ADV_CCB *adv_get_ccb(ASC_SOFTC *, int);
! 81: static void adv_queue_ccb(ASC_SOFTC *, ADV_CCB *);
! 82: static void adv_start_ccbs(ASC_SOFTC *);
! 83:
! 84: static u_int8_t *adv_alloc_overrunbuf(char *dvname, bus_dma_tag_t);
! 85:
! 86: static int adv_scsi_cmd(struct scsi_xfer *);
! 87: static void advminphys(struct buf *);
! 88: static void adv_narrow_isr_callback(ASC_SOFTC *, ASC_QDONE_INFO *);
! 89:
! 90: static int adv_poll(ASC_SOFTC *, struct scsi_xfer *, int);
! 91: static void adv_timeout(void *);
! 92: static void adv_watchdog(void *);
! 93:
! 94:
! 95: /******************************************************************************/
! 96:
! 97:
! 98: struct cfdriver adv_cd = {
! 99: NULL, "adv", DV_DULL
! 100: };
! 101:
! 102:
! 103: struct scsi_adapter adv_switch =
! 104: {
! 105: adv_scsi_cmd, /* called to start/enqueue a SCSI command */
! 106: advminphys, /* to limit the transfer to max device can do */
! 107: 0, /* IT SEEMS IT IS NOT USED YET */
! 108: 0, /* as above... */
! 109: };
! 110:
! 111:
! 112: /* the below structure is so we have a default dev struct for out link struct */
! 113: struct scsi_device adv_dev =
! 114: {
! 115: NULL, /* Use default error handler */
! 116: NULL, /* have a queue, served by this */
! 117: NULL, /* have no async handler */
! 118: NULL, /* Use default 'done' routine */
! 119: };
! 120:
! 121:
! 122: #define ADV_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
! 123: #define ADV_WATCH_TIMEOUT 1000 /* time to wait for watchdog (mSec) */
! 124:
! 125:
! 126: /******************************************************************************/
! 127: /* scsi_xfer queue routines */
! 128: /******************************************************************************/
! 129:
! 130:
! 131: /*
! 132: * Insert a scsi_xfer into the software queue. We overload xs->free_list
! 133: * to avoid having to allocate additional resources (since we're used
! 134: * only during resource shortages anyhow.
! 135: */
! 136: static void
! 137: adv_enqueue(sc, xs, infront)
! 138: ASC_SOFTC *sc;
! 139: struct scsi_xfer *xs;
! 140: int infront;
! 141: {
! 142:
! 143: if (infront || LIST_EMPTY(&sc->sc_queue)) {
! 144: if (LIST_EMPTY(&sc->sc_queue))
! 145: sc->sc_queuelast = xs;
! 146: LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
! 147: return;
! 148: }
! 149: LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
! 150: sc->sc_queuelast = xs;
! 151: }
! 152:
! 153:
! 154: /*
! 155: * Pull a scsi_xfer off the front of the software queue.
! 156: */
! 157: static struct scsi_xfer *
! 158: adv_dequeue(sc)
! 159: ASC_SOFTC *sc;
! 160: {
! 161: struct scsi_xfer *xs;
! 162:
! 163: xs = LIST_FIRST(&sc->sc_queue);
! 164: LIST_REMOVE(xs, free_list);
! 165:
! 166: if (LIST_EMPTY(&sc->sc_queue))
! 167: sc->sc_queuelast = NULL;
! 168:
! 169: return (xs);
! 170: }
! 171:
! 172:
! 173: /******************************************************************************/
! 174: /* Control Blocks routines */
! 175: /******************************************************************************/
! 176:
! 177:
! 178: static int
! 179: adv_alloc_ccbs(sc)
! 180: ASC_SOFTC *sc;
! 181: {
! 182: bus_dma_segment_t seg;
! 183: int error, rseg;
! 184:
! 185: /*
! 186: * Allocate the control blocks.
! 187: */
! 188: if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct adv_control),
! 189: NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 190: printf("%s: unable to allocate control structures,"
! 191: " error = %d\n", sc->sc_dev.dv_xname, error);
! 192: return (error);
! 193: }
! 194: if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
! 195: sizeof(struct adv_control), (caddr_t *) & sc->sc_control,
! 196: BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
! 197: printf("%s: unable to map control structures, error = %d\n",
! 198: sc->sc_dev.dv_xname, error);
! 199: return (error);
! 200: }
! 201: /*
! 202: * Create and load the DMA map used for the control blocks.
! 203: */
! 204: if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct adv_control),
! 205: 1, sizeof(struct adv_control), 0, BUS_DMA_NOWAIT,
! 206: &sc->sc_dmamap_control)) != 0) {
! 207: printf("%s: unable to create control DMA map, error = %d\n",
! 208: sc->sc_dev.dv_xname, error);
! 209: return (error);
! 210: }
! 211: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_control,
! 212: sc->sc_control, sizeof(struct adv_control), NULL,
! 213: BUS_DMA_NOWAIT)) != 0) {
! 214: printf("%s: unable to load control DMA map, error = %d\n",
! 215: sc->sc_dev.dv_xname, error);
! 216: return (error);
! 217: }
! 218: return (0);
! 219: }
! 220:
! 221:
! 222: /*
! 223: * Create a set of ccbs and add them to the free list. Called once
! 224: * by adv_init(). We return the number of CCBs successfully created.
! 225: */
! 226: static int
! 227: adv_create_ccbs(sc, ccbstore, count)
! 228: ASC_SOFTC *sc;
! 229: ADV_CCB *ccbstore;
! 230: int count;
! 231: {
! 232: ADV_CCB *ccb;
! 233: int i, error;
! 234:
! 235: bzero(ccbstore, sizeof(ADV_CCB) * count);
! 236: for (i = 0; i < count; i++) {
! 237: ccb = &ccbstore[i];
! 238: if ((error = adv_init_ccb(sc, ccb)) != 0) {
! 239: printf("%s: unable to initialize ccb, error = %d\n",
! 240: sc->sc_dev.dv_xname, error);
! 241: return (i);
! 242: }
! 243: TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
! 244: }
! 245:
! 246: return (i);
! 247: }
! 248:
! 249:
! 250: /*
! 251: * A ccb is put onto the free list.
! 252: */
! 253: static void
! 254: adv_free_ccb(sc, ccb)
! 255: ASC_SOFTC *sc;
! 256: ADV_CCB *ccb;
! 257: {
! 258: int s;
! 259:
! 260: s = splbio();
! 261:
! 262: adv_reset_ccb(ccb);
! 263: TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
! 264:
! 265: /*
! 266: * If there were none, wake anybody waiting for one to come free,
! 267: * starting with queued entries.
! 268: */
! 269: if (TAILQ_NEXT(ccb, chain) == NULL)
! 270: wakeup(&sc->sc_free_ccb);
! 271:
! 272: splx(s);
! 273: }
! 274:
! 275:
! 276: static void
! 277: adv_reset_ccb(ccb)
! 278: ADV_CCB *ccb;
! 279: {
! 280:
! 281: ccb->flags = 0;
! 282: }
! 283:
! 284:
! 285: static int
! 286: adv_init_ccb(sc, ccb)
! 287: ASC_SOFTC *sc;
! 288: ADV_CCB *ccb;
! 289: {
! 290: int error;
! 291:
! 292: /*
! 293: * Create the DMA map for this CCB.
! 294: */
! 295: error = bus_dmamap_create(sc->sc_dmat,
! 296: (ASC_MAX_SG_LIST - 1) * PAGE_SIZE,
! 297: ASC_MAX_SG_LIST, (ASC_MAX_SG_LIST - 1) * PAGE_SIZE,
! 298: 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer);
! 299: if (error) {
! 300: printf("%s: unable to create DMA map, error = %d\n",
! 301: sc->sc_dev.dv_xname, error);
! 302: return (error);
! 303: }
! 304: adv_reset_ccb(ccb);
! 305: return (0);
! 306: }
! 307:
! 308:
! 309: /*
! 310: * Get a free ccb
! 311: *
! 312: * If there are none, see if we can allocate a new one
! 313: */
! 314: static ADV_CCB *
! 315: adv_get_ccb(sc, flags)
! 316: ASC_SOFTC *sc;
! 317: int flags;
! 318: {
! 319: ADV_CCB *ccb = 0;
! 320: int s;
! 321:
! 322: s = splbio();
! 323:
! 324: /*
! 325: * If we can and have to, sleep waiting for one to come free
! 326: * but only if we can't allocate a new one.
! 327: */
! 328: for (;;) {
! 329: ccb = TAILQ_FIRST(&sc->sc_free_ccb);
! 330: if (ccb) {
! 331: TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
! 332: break;
! 333: }
! 334: if ((flags & SCSI_NOSLEEP) != 0)
! 335: goto out;
! 336:
! 337: tsleep(&sc->sc_free_ccb, PRIBIO, "advccb", 0);
! 338: }
! 339:
! 340: ccb->flags |= CCB_ALLOC;
! 341:
! 342: out:
! 343: splx(s);
! 344: return (ccb);
! 345: }
! 346:
! 347:
! 348: /*
! 349: * Queue a CCB to be sent to the controller, and send it if possible.
! 350: */
! 351: static void
! 352: adv_queue_ccb(sc, ccb)
! 353: ASC_SOFTC *sc;
! 354: ADV_CCB *ccb;
! 355: {
! 356:
! 357: timeout_set(&ccb->xs->stimeout, adv_timeout, ccb);
! 358: TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
! 359:
! 360: adv_start_ccbs(sc);
! 361: }
! 362:
! 363:
! 364: static void
! 365: adv_start_ccbs(sc)
! 366: ASC_SOFTC *sc;
! 367: {
! 368: ADV_CCB *ccb;
! 369: struct scsi_xfer *xs;
! 370:
! 371: while ((ccb = TAILQ_FIRST(&sc->sc_waiting_ccb)) != NULL) {
! 372:
! 373: xs = ccb->xs;
! 374: if (ccb->flags & CCB_WATCHDOG)
! 375: timeout_del(&xs->stimeout);
! 376:
! 377: if (AscExeScsiQueue(sc, &ccb->scsiq) == ASC_BUSY) {
! 378: ccb->flags |= CCB_WATCHDOG;
! 379: timeout_set(&xs->stimeout, adv_watchdog, ccb);
! 380: timeout_add(&xs->stimeout,
! 381: (ADV_WATCH_TIMEOUT * hz) / 1000);
! 382: break;
! 383: }
! 384: TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
! 385:
! 386: if ((ccb->xs->flags & SCSI_POLL) == 0) {
! 387: timeout_set(&xs->stimeout, adv_timeout, ccb);
! 388: timeout_add(&xs->stimeout, (ccb->timeout * hz) / 1000);
! 389: }
! 390: }
! 391: }
! 392:
! 393:
! 394: /******************************************************************************/
! 395: /* DMA able memory allocation routines */
! 396: /******************************************************************************/
! 397:
! 398:
! 399: /*
! 400: * Allocate a DMA able memory for overrun_buffer.
! 401: * This memory can be safely shared among all the AdvanSys boards.
! 402: */
! 403: u_int8_t *
! 404: adv_alloc_overrunbuf(dvname, dmat)
! 405: char *dvname;
! 406: bus_dma_tag_t dmat;
! 407: {
! 408: static u_int8_t *overrunbuf = NULL;
! 409:
! 410: bus_dmamap_t ovrbuf_dmamap;
! 411: bus_dma_segment_t seg;
! 412: int rseg, error;
! 413:
! 414:
! 415: /*
! 416: * if an overrun buffer has been already allocated don't allocate it
! 417: * again. Instead return the address of the allocated buffer.
! 418: */
! 419: if (overrunbuf)
! 420: return (overrunbuf);
! 421:
! 422:
! 423: if ((error = bus_dmamem_alloc(dmat, ASC_OVERRUN_BSIZE,
! 424: NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 425: printf("%s: unable to allocate overrun buffer, error = %d\n",
! 426: dvname, error);
! 427: return (0);
! 428: }
! 429: if ((error = bus_dmamem_map(dmat, &seg, rseg, ASC_OVERRUN_BSIZE,
! 430: (caddr_t *) & overrunbuf, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
! 431: printf("%s: unable to map overrun buffer, error = %d\n",
! 432: dvname, error);
! 433:
! 434: bus_dmamem_free(dmat, &seg, 1);
! 435: return (0);
! 436: }
! 437: if ((error = bus_dmamap_create(dmat, ASC_OVERRUN_BSIZE, 1,
! 438: ASC_OVERRUN_BSIZE, 0, BUS_DMA_NOWAIT, &ovrbuf_dmamap)) != 0) {
! 439: printf("%s: unable to create overrun buffer DMA map,"
! 440: " error = %d\n", dvname, error);
! 441:
! 442: bus_dmamem_unmap(dmat, overrunbuf, ASC_OVERRUN_BSIZE);
! 443: bus_dmamem_free(dmat, &seg, 1);
! 444: return (0);
! 445: }
! 446: if ((error = bus_dmamap_load(dmat, ovrbuf_dmamap, overrunbuf,
! 447: ASC_OVERRUN_BSIZE, NULL, BUS_DMA_NOWAIT)) != 0) {
! 448: printf("%s: unable to load overrun buffer DMA map,"
! 449: " error = %d\n", dvname, error);
! 450:
! 451: bus_dmamap_destroy(dmat, ovrbuf_dmamap);
! 452: bus_dmamem_unmap(dmat, overrunbuf, ASC_OVERRUN_BSIZE);
! 453: bus_dmamem_free(dmat, &seg, 1);
! 454: return (0);
! 455: }
! 456: return (overrunbuf);
! 457: }
! 458:
! 459:
! 460: /******************************************************************************/
! 461: /* SCSI layer interfacing routines */
! 462: /******************************************************************************/
! 463:
! 464:
! 465: int
! 466: adv_init(sc)
! 467: ASC_SOFTC *sc;
! 468: {
! 469: int warn;
! 470:
! 471: if (!AscFindSignature(sc->sc_iot, sc->sc_ioh))
! 472: panic("adv_init: adv_find_signature failed");
! 473:
! 474: /*
! 475: * Read the board configuration
! 476: */
! 477: AscInitASC_SOFTC(sc);
! 478: warn = AscInitFromEEP(sc);
! 479: if (warn) {
! 480: printf("%s -get: ", sc->sc_dev.dv_xname);
! 481: switch (warn) {
! 482: case -1:
! 483: printf("Chip is not halted\n");
! 484: break;
! 485:
! 486: case -2:
! 487: printf("Couldn't get MicroCode Start"
! 488: " address\n");
! 489: break;
! 490:
! 491: case ASC_WARN_IO_PORT_ROTATE:
! 492: printf("I/O port address modified\n");
! 493: break;
! 494:
! 495: case ASC_WARN_AUTO_CONFIG:
! 496: printf("I/O port increment switch enabled\n");
! 497: break;
! 498:
! 499: case ASC_WARN_EEPROM_CHKSUM:
! 500: printf("EEPROM checksum error\n");
! 501: break;
! 502:
! 503: case ASC_WARN_IRQ_MODIFIED:
! 504: printf("IRQ modified\n");
! 505: break;
! 506:
! 507: case ASC_WARN_CMD_QNG_CONFLICT:
! 508: printf("tag queuing enabled w/o disconnects\n");
! 509: break;
! 510:
! 511: default:
! 512: printf("unknown warning %d\n", warn);
! 513: }
! 514: }
! 515: if (sc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
! 516: sc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
! 517:
! 518: /*
! 519: * Modify the board configuration
! 520: */
! 521: warn = AscInitFromASC_SOFTC(sc);
! 522: if (warn) {
! 523: printf("%s -set: ", sc->sc_dev.dv_xname);
! 524: switch (warn) {
! 525: case ASC_WARN_CMD_QNG_CONFLICT:
! 526: printf("tag queuing enabled w/o disconnects\n");
! 527: break;
! 528:
! 529: case ASC_WARN_AUTO_CONFIG:
! 530: printf("I/O port increment switch enabled\n");
! 531: break;
! 532:
! 533: default:
! 534: printf("unknown warning %d\n", warn);
! 535: }
! 536: }
! 537: sc->isr_callback = (ulong) adv_narrow_isr_callback;
! 538:
! 539: if (!(sc->overrun_buf = adv_alloc_overrunbuf(sc->sc_dev.dv_xname,
! 540: sc->sc_dmat))) {
! 541: return (1);
! 542: }
! 543:
! 544: return (0);
! 545: }
! 546:
! 547:
! 548: void
! 549: adv_attach(sc)
! 550: ASC_SOFTC *sc;
! 551: {
! 552: struct scsibus_attach_args saa;
! 553: int i, error;
! 554:
! 555: /*
! 556: * Initialize board RISC chip and enable interrupts.
! 557: */
! 558: switch (AscInitDriver(sc)) {
! 559: case 0:
! 560: /* AllOK */
! 561: break;
! 562:
! 563: case 1:
! 564: panic("%s: bad signature", sc->sc_dev.dv_xname);
! 565: break;
! 566:
! 567: case 2:
! 568: panic("%s: unable to load MicroCode",
! 569: sc->sc_dev.dv_xname);
! 570: break;
! 571:
! 572: case 3:
! 573: panic("%s: unable to initialize MicroCode",
! 574: sc->sc_dev.dv_xname);
! 575: break;
! 576:
! 577: default:
! 578: panic("%s: unable to initialize board RISC chip",
! 579: sc->sc_dev.dv_xname);
! 580: }
! 581:
! 582:
! 583: /*
! 584: * fill in the prototype scsi_link.
! 585: */
! 586: sc->sc_link.adapter_softc = sc;
! 587: sc->sc_link.adapter_target = sc->chip_scsi_id;
! 588: sc->sc_link.adapter = &adv_switch;
! 589: sc->sc_link.device = &adv_dev;
! 590: sc->sc_link.openings = 4;
! 591: sc->sc_link.adapter_buswidth = 7;
! 592:
! 593:
! 594: TAILQ_INIT(&sc->sc_free_ccb);
! 595: TAILQ_INIT(&sc->sc_waiting_ccb);
! 596: LIST_INIT(&sc->sc_queue);
! 597:
! 598:
! 599: /*
! 600: * Allocate the Control Blocks.
! 601: */
! 602: error = adv_alloc_ccbs(sc);
! 603: if (error)
! 604: return; /* (error) */ ;
! 605:
! 606: /*
! 607: * Create and initialize the Control Blocks.
! 608: */
! 609: i = adv_create_ccbs(sc, sc->sc_control->ccbs, ADV_MAX_CCB);
! 610: if (i == 0) {
! 611: printf("%s: unable to create control blocks\n",
! 612: sc->sc_dev.dv_xname);
! 613: return; /* (ENOMEM) */ ;
! 614: } else if (i != ADV_MAX_CCB) {
! 615: printf("%s: WARNING: only %d of %d control blocks created\n",
! 616: sc->sc_dev.dv_xname, i, ADV_MAX_CCB);
! 617: }
! 618:
! 619: bzero(&saa, sizeof(saa));
! 620: saa.saa_sc_link = &sc->sc_link;
! 621: config_found(&sc->sc_dev, &saa, scsiprint);
! 622: }
! 623:
! 624:
! 625: static void
! 626: advminphys(bp)
! 627: struct buf *bp;
! 628: {
! 629:
! 630: if (bp->b_bcount > ((ASC_MAX_SG_LIST - 1) * PAGE_SIZE))
! 631: bp->b_bcount = ((ASC_MAX_SG_LIST - 1) * PAGE_SIZE);
! 632: minphys(bp);
! 633: }
! 634:
! 635:
! 636: /*
! 637: * start a scsi operation given the command and the data address. Also needs
! 638: * the unit, target and lu.
! 639: */
! 640: static int
! 641: adv_scsi_cmd(xs)
! 642: struct scsi_xfer *xs;
! 643: {
! 644: struct scsi_link *sc_link = xs->sc_link;
! 645: ASC_SOFTC *sc = sc_link->adapter_softc;
! 646: bus_dma_tag_t dmat = sc->sc_dmat;
! 647: ADV_CCB *ccb;
! 648: int s, flags, error, nsegs;
! 649: int fromqueue = 1, dontqueue = 0;
! 650:
! 651:
! 652: s = splbio(); /* protect the queue */
! 653:
! 654: /*
! 655: * If we're running the queue from adv_done(), we've been
! 656: * called with the first queue entry as our argument.
! 657: */
! 658: if (xs == LIST_FIRST(&sc->sc_queue)) {
! 659: xs = adv_dequeue(sc);
! 660: fromqueue = 1;
! 661: } else {
! 662:
! 663: /* Polled requests can't be queued for later. */
! 664: dontqueue = xs->flags & SCSI_POLL;
! 665:
! 666: /*
! 667: * If there are jobs in the queue, run them first.
! 668: */
! 669: if (!LIST_EMPTY(&sc->sc_queue)) {
! 670: /*
! 671: * If we can't queue, we have to abort, since
! 672: * we have to preserve order.
! 673: */
! 674: if (dontqueue) {
! 675: splx(s);
! 676: return (TRY_AGAIN_LATER);
! 677: }
! 678: /*
! 679: * Swap with the first queue entry.
! 680: */
! 681: adv_enqueue(sc, xs, 0);
! 682: xs = adv_dequeue(sc);
! 683: fromqueue = 1;
! 684: }
! 685: }
! 686:
! 687:
! 688: /*
! 689: * get a ccb to use. If the transfer
! 690: * is from a buf (possibly from interrupt time)
! 691: * then we can't allow it to sleep
! 692: */
! 693:
! 694: flags = xs->flags;
! 695: if ((ccb = adv_get_ccb(sc, flags)) == NULL) {
! 696: /*
! 697: * If we can't queue, we lose.
! 698: */
! 699: if (dontqueue) {
! 700: splx(s);
! 701: return (TRY_AGAIN_LATER);
! 702: }
! 703: /*
! 704: * Stuff ourselves into the queue, in front
! 705: * if we came off in the first place.
! 706: */
! 707: adv_enqueue(sc, xs, fromqueue);
! 708: splx(s);
! 709: return (SUCCESSFULLY_QUEUED);
! 710: }
! 711: splx(s); /* done playing with the queue */
! 712:
! 713: ccb->xs = xs;
! 714: ccb->timeout = xs->timeout;
! 715:
! 716: /*
! 717: * Build up the request
! 718: */
! 719: memset(&ccb->scsiq, 0, sizeof(ASC_SCSI_Q));
! 720:
! 721: ccb->scsiq.q2.ccb_ptr = (ulong) ccb;
! 722:
! 723: ccb->scsiq.cdbptr = &xs->cmd->opcode;
! 724: ccb->scsiq.q2.cdb_len = xs->cmdlen;
! 725: ccb->scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(sc_link->target);
! 726: ccb->scsiq.q1.target_lun = sc_link->lun;
! 727: ccb->scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(sc_link->target,
! 728: sc_link->lun);
! 729: ccb->scsiq.q1.sense_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 730: ADV_CCB_OFF(ccb) + offsetof(struct adv_ccb, scsi_sense);
! 731: ccb->scsiq.q1.sense_len = sizeof(struct scsi_sense_data);
! 732:
! 733: /*
! 734: * If there are any outstanding requests for the current target,
! 735: * then every 255th request send an ORDERED request. This heuristic
! 736: * tries to retain the benefit of request sorting while preventing
! 737: * request starvation. 255 is the max number of tags or pending commands
! 738: * a device may have outstanding.
! 739: */
! 740: sc->reqcnt[sc_link->target]++;
! 741: if ((sc->reqcnt[sc_link->target] > 0) &&
! 742: (sc->reqcnt[sc_link->target] % 255) == 0) {
! 743: ccb->scsiq.q2.tag_code = M2_QTAG_MSG_ORDERED;
! 744: } else {
! 745: ccb->scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
! 746: }
! 747:
! 748:
! 749: if (xs->datalen) {
! 750: /*
! 751: * Map the DMA transfer.
! 752: */
! 753: #ifdef TFS
! 754: if (flags & SCSI_DATA_UIO) {
! 755: error = bus_dmamap_load_uio(dmat,
! 756: ccb->dmamap_xfer, (struct uio *) xs->data,
! 757: (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
! 758: } else
! 759: #endif /* TFS */
! 760: {
! 761: error = bus_dmamap_load(dmat,
! 762: ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
! 763: (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
! 764: }
! 765:
! 766: if (error) {
! 767: if (error == EFBIG) {
! 768: printf("%s: adv_scsi_cmd, more than %d dma"
! 769: " segments\n",
! 770: sc->sc_dev.dv_xname, ASC_MAX_SG_LIST);
! 771: } else {
! 772: printf("%s: adv_scsi_cmd, error %d loading"
! 773: " dma map\n",
! 774: sc->sc_dev.dv_xname, error);
! 775: }
! 776:
! 777: xs->error = XS_DRIVER_STUFFUP;
! 778: adv_free_ccb(sc, ccb);
! 779: return (COMPLETE);
! 780: }
! 781: bus_dmamap_sync(dmat, ccb->dmamap_xfer,
! 782: 0, ccb->dmamap_xfer->dm_mapsize,
! 783: ((flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
! 784: BUS_DMASYNC_PREWRITE));
! 785:
! 786:
! 787: memset(&ccb->sghead, 0, sizeof(ASC_SG_HEAD));
! 788:
! 789: for (nsegs = 0; nsegs < ccb->dmamap_xfer->dm_nsegs; nsegs++) {
! 790:
! 791: ccb->sghead.sg_list[nsegs].addr =
! 792: ccb->dmamap_xfer->dm_segs[nsegs].ds_addr;
! 793: ccb->sghead.sg_list[nsegs].bytes =
! 794: ccb->dmamap_xfer->dm_segs[nsegs].ds_len;
! 795: }
! 796:
! 797: ccb->sghead.entry_cnt = ccb->scsiq.q1.sg_queue_cnt =
! 798: ccb->dmamap_xfer->dm_nsegs;
! 799:
! 800: ccb->scsiq.q1.cntl |= ASC_QC_SG_HEAD;
! 801: ccb->scsiq.sg_head = &ccb->sghead;
! 802: ccb->scsiq.q1.data_addr = 0;
! 803: ccb->scsiq.q1.data_cnt = 0;
! 804: } else {
! 805: /*
! 806: * No data xfer, use non S/G values.
! 807: */
! 808: ccb->scsiq.q1.data_addr = 0;
! 809: ccb->scsiq.q1.data_cnt = 0;
! 810: }
! 811:
! 812: #ifdef ASC_DEBUG
! 813: printf("id = %d, lun = %d, cmd = %d, ccb = 0x%lX \n",
! 814: sc_link->scsipi_scsi.target,
! 815: sc_link->scsipi_scsi.lun, xs->cmd->opcode,
! 816: (unsigned long)ccb);
! 817: #endif
! 818: s = splbio();
! 819: adv_queue_ccb(sc, ccb);
! 820: splx(s);
! 821:
! 822: /*
! 823: * Usually return SUCCESSFULLY QUEUED
! 824: */
! 825: if ((flags & SCSI_POLL) == 0)
! 826: return (SUCCESSFULLY_QUEUED);
! 827:
! 828: /*
! 829: * If we can't use interrupts, poll on completion
! 830: */
! 831: if (adv_poll(sc, xs, ccb->timeout)) {
! 832: adv_timeout(ccb);
! 833: if (adv_poll(sc, xs, ccb->timeout))
! 834: adv_timeout(ccb);
! 835: }
! 836: return (COMPLETE);
! 837: }
! 838:
! 839:
! 840: int
! 841: adv_intr(arg)
! 842: void *arg;
! 843: {
! 844: ASC_SOFTC *sc = arg;
! 845: struct scsi_xfer *xs;
! 846:
! 847: #ifdef ASC_DEBUG
! 848: int int_pend = FALSE;
! 849:
! 850: if(ASC_IS_INT_PENDING(sc->sc_iot, sc->sc_ioh))
! 851: {
! 852: int_pend = TRUE;
! 853: printf("ISR - ");
! 854: }
! 855: #endif
! 856: AscISR(sc);
! 857: #ifdef ASC_DEBUG
! 858: if(int_pend)
! 859: printf("\n");
! 860: #endif
! 861:
! 862: /*
! 863: * If there are queue entries in the software queue, try to
! 864: * run the first one. We should be more or less guaranteed
! 865: * to succeed, since we just freed a CCB.
! 866: *
! 867: * NOTE: adv_scsi_cmd() relies on our calling it with
! 868: * the first entry in the queue.
! 869: */
! 870: if ((xs = LIST_FIRST(&sc->sc_queue)) != NULL)
! 871: (void) adv_scsi_cmd(xs);
! 872:
! 873: return (1);
! 874: }
! 875:
! 876:
! 877: /*
! 878: * Poll a particular unit, looking for a particular xs
! 879: */
! 880: static int
! 881: adv_poll(sc, xs, count)
! 882: ASC_SOFTC *sc;
! 883: struct scsi_xfer *xs;
! 884: int count;
! 885: {
! 886:
! 887: /* timeouts are in msec, so we loop in 1000 usec cycles */
! 888: while (count) {
! 889: adv_intr(sc);
! 890: if (xs->flags & ITSDONE)
! 891: return (0);
! 892: delay(1000); /* only happens in boot so ok */
! 893: count--;
! 894: }
! 895: return (1);
! 896: }
! 897:
! 898:
! 899: static void
! 900: adv_timeout(arg)
! 901: void *arg;
! 902: {
! 903: ADV_CCB *ccb = arg;
! 904: struct scsi_xfer *xs = ccb->xs;
! 905: struct scsi_link *sc_link = xs->sc_link;
! 906: ASC_SOFTC *sc = sc_link->adapter_softc;
! 907: int s;
! 908:
! 909: sc_print_addr(sc_link);
! 910: printf("timed out");
! 911:
! 912: s = splbio();
! 913:
! 914: /*
! 915: * If it has been through before, then a previous abort has failed,
! 916: * don't try abort again, reset the bus instead.
! 917: */
! 918: if (ccb->flags & CCB_ABORT) {
! 919: /* abort timed out */
! 920: printf(" AGAIN. Resetting Bus\n");
! 921: /* Lets try resetting the bus! */
! 922: if (AscResetBus(sc) == ASC_ERROR) {
! 923: ccb->timeout = sc->scsi_reset_wait;
! 924: adv_queue_ccb(sc, ccb);
! 925: }
! 926: } else {
! 927: /* abort the operation that has timed out */
! 928: printf("\n");
! 929: AscAbortCCB(sc, (u_int32_t) ccb);
! 930: ccb->xs->error = XS_TIMEOUT;
! 931: ccb->timeout = ADV_ABORT_TIMEOUT;
! 932: ccb->flags |= CCB_ABORT;
! 933: adv_queue_ccb(sc, ccb);
! 934: }
! 935:
! 936: splx(s);
! 937: }
! 938:
! 939:
! 940: static void
! 941: adv_watchdog(arg)
! 942: void *arg;
! 943: {
! 944: ADV_CCB *ccb = arg;
! 945: struct scsi_xfer *xs = ccb->xs;
! 946: struct scsi_link *sc_link = xs->sc_link;
! 947: ASC_SOFTC *sc = sc_link->adapter_softc;
! 948: int s;
! 949:
! 950: s = splbio();
! 951:
! 952: ccb->flags &= ~CCB_WATCHDOG;
! 953: adv_start_ccbs(sc);
! 954:
! 955: splx(s);
! 956: }
! 957:
! 958:
! 959: /******************************************************************************/
! 960: /* NARROW and WIDE boards Interrupt callbacks */
! 961: /******************************************************************************/
! 962:
! 963:
! 964: /*
! 965: * adv_narrow_isr_callback() - Second Level Interrupt Handler called by AscISR()
! 966: *
! 967: * Interrupt callback function for the Narrow SCSI Asc Library.
! 968: */
! 969: static void
! 970: adv_narrow_isr_callback(sc, qdonep)
! 971: ASC_SOFTC *sc;
! 972: ASC_QDONE_INFO *qdonep;
! 973: {
! 974: bus_dma_tag_t dmat = sc->sc_dmat;
! 975: ADV_CCB *ccb = (ADV_CCB *) qdonep->d2.ccb_ptr;
! 976: struct scsi_xfer *xs = ccb->xs;
! 977: struct scsi_sense_data *s1, *s2;
! 978:
! 979:
! 980: #ifdef ASC_DEBUG
! 981: printf(" - ccb=0x%lx, id=%d, lun=%d, cmd=%d, ",
! 982: (unsigned long)ccb,
! 983: xs->sc_link->scsipi_scsi.target,
! 984: xs->sc_link->scsipi_scsi.lun, xs->cmd->opcode);
! 985: #endif
! 986: timeout_del(&xs->stimeout);
! 987:
! 988: /*
! 989: * If we were a data transfer, unload the map that described
! 990: * the data buffer.
! 991: */
! 992: if (xs->datalen) {
! 993: bus_dmamap_sync(dmat, ccb->dmamap_xfer,
! 994: 0, ccb->dmamap_xfer->dm_mapsize,
! 995: ((xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
! 996: BUS_DMASYNC_POSTWRITE));
! 997: bus_dmamap_unload(dmat, ccb->dmamap_xfer);
! 998: }
! 999: if ((ccb->flags & CCB_ALLOC) == 0) {
! 1000: printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
! 1001: Debugger();
! 1002: return;
! 1003: }
! 1004: /*
! 1005: * 'qdonep' contains the command's ending status.
! 1006: */
! 1007: #ifdef ASC_DEBUG
! 1008: printf("d_s=%d, h_s=%d", qdonep->d3.done_stat, qdonep->d3.host_stat);
! 1009: #endif
! 1010: switch (qdonep->d3.done_stat) {
! 1011: case ASC_QD_NO_ERROR:
! 1012: switch (qdonep->d3.host_stat) {
! 1013: case ASC_QHSTA_NO_ERROR:
! 1014: xs->error = XS_NOERROR;
! 1015: xs->resid = 0;
! 1016: break;
! 1017:
! 1018: default:
! 1019: /* QHSTA error occurred */
! 1020: xs->error = XS_DRIVER_STUFFUP;
! 1021: break;
! 1022: }
! 1023:
! 1024: /*
! 1025: * If an INQUIRY command completed successfully, then call
! 1026: * the AscInquiryHandling() function to patch bugged boards.
! 1027: */
! 1028: if ((xs->cmd->opcode == SCSICMD_Inquiry) &&
! 1029: (xs->sc_link->lun == 0) &&
! 1030: (xs->datalen - qdonep->remain_bytes) >= 8) {
! 1031: AscInquiryHandling(sc,
! 1032: xs->sc_link->target & 0x7,
! 1033: (ASC_SCSI_INQUIRY *) xs->data);
! 1034: }
! 1035: break;
! 1036:
! 1037: case ASC_QD_WITH_ERROR:
! 1038: switch (qdonep->d3.host_stat) {
! 1039: case ASC_QHSTA_NO_ERROR:
! 1040: if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
! 1041: s1 = &ccb->scsi_sense;
! 1042: s2 = &xs->sense;
! 1043: *s2 = *s1;
! 1044: xs->error = XS_SENSE;
! 1045: } else {
! 1046: xs->error = XS_DRIVER_STUFFUP;
! 1047: }
! 1048: break;
! 1049:
! 1050: default:
! 1051: /* QHSTA error occurred */
! 1052: xs->error = XS_DRIVER_STUFFUP;
! 1053: break;
! 1054: }
! 1055: break;
! 1056:
! 1057: case ASC_QD_ABORTED_BY_HOST:
! 1058: default:
! 1059: xs->error = XS_DRIVER_STUFFUP;
! 1060: break;
! 1061: }
! 1062:
! 1063:
! 1064: adv_free_ccb(sc, ccb);
! 1065: xs->flags |= ITSDONE;
! 1066: scsi_done(xs);
! 1067: }
CVSweb