1 /* $NetBSD: spifi.c,v 1.6 2002/03/06 16:50:34 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/buf.h> 31 #include <sys/device.h> 32 #include <sys/errno.h> 33 #include <sys/kernel.h> 34 #include <sys/queue.h> 35 #include <sys/systm.h> 36 37 #include <uvm/uvm_extern.h> 38 39 #include <dev/scsipi/scsi_all.h> 40 #include <dev/scsipi/scsi_message.h> 41 #include <dev/scsipi/scsipi_all.h> 42 #include <dev/scsipi/scsiconf.h> 43 44 #include <newsmips/apbus/apbusvar.h> 45 #include <newsmips/apbus/spifireg.h> 46 #include <newsmips/apbus/dmac3reg.h> 47 48 #include <machine/adrsmap.h> 49 50 /* #define SPIFI_DEBUG */ 51 52 #ifdef SPIFI_DEBUG 53 # define DPRINTF printf 54 #else 55 # define DPRINTF while (0) printf 56 #endif 57 58 struct spifi_scb { 59 TAILQ_ENTRY(spifi_scb) chain; 60 int flags; 61 struct scsipi_xfer *xs; 62 struct scsi_generic cmd; 63 int cmdlen; 64 int resid; 65 vaddr_t daddr; 66 u_char target; 67 u_char lun; 68 u_char lun_targ; 69 u_char status; 70 }; 71 /* scb flags */ 72 #define SPIFI_READ 0x80 73 #define SPIFI_DMA 0x01 74 75 struct spifi_softc { 76 struct device sc_dev; 77 struct scsipi_channel sc_channel; 78 struct scsipi_adapter sc_adapter; 79 80 struct spifi_reg *sc_reg; 81 struct spifi_scb *sc_nexus; 82 void *sc_dma; /* attached DMA softc */ 83 int sc_id; /* my SCSI ID */ 84 int sc_msgout; 85 u_char sc_omsg[16]; 86 struct spifi_scb sc_scb[16]; 87 TAILQ_HEAD(, spifi_scb) free_scb; 88 TAILQ_HEAD(, spifi_scb) ready_scb; 89 }; 90 91 #define SPIFI_SYNC_OFFSET_MAX 7 92 93 #define SEND_REJECT 1 94 #define SEND_IDENTIFY 2 95 #define SEND_SDTR 4 96 97 #define SPIFI_DATAOUT 0 98 #define SPIFI_DATAIN PRS_IO 99 #define SPIFI_COMMAND PRS_CD 100 #define SPIFI_STATUS (PRS_CD | PRS_IO) 101 #define SPIFI_MSGOUT (PRS_MSG | PRS_CD) 102 #define SPIFI_MSGIN (PRS_MSG | PRS_CD | PRS_IO) 103 104 int spifi_match(struct device *, struct cfdata *, void *); 105 void spifi_attach(struct device *, struct device *, void *); 106 107 void spifi_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, void *); 108 struct spifi_scb *spifi_get_scb(struct spifi_softc *); 109 void spifi_free_scb(struct spifi_softc *, struct spifi_scb *); 110 int spifi_poll(struct spifi_softc *); 111 void spifi_minphys(struct buf *); 112 113 void spifi_sched(struct spifi_softc *); 114 int spifi_intr(void *); 115 void spifi_pmatch(struct spifi_softc *); 116 117 void spifi_select(struct spifi_softc *); 118 void spifi_sendmsg(struct spifi_softc *, int); 119 void spifi_command(struct spifi_softc *); 120 void spifi_data_io(struct spifi_softc *); 121 void spifi_status(struct spifi_softc *); 122 int spifi_done(struct spifi_softc *); 123 void spifi_fifo_drain(struct spifi_softc *); 124 void spifi_reset(struct spifi_softc *); 125 void spifi_bus_reset(struct spifi_softc *); 126 127 static int spifi_read_count(struct spifi_reg *); 128 static void spifi_write_count(struct spifi_reg *, int); 129 130 #define DMAC3_FASTACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_FASTACCESS) 131 #define DMAC3_SLOWACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_SLOWACCESS) 132 133 struct cfattach spifi_ca = { 134 sizeof(struct spifi_softc), spifi_match, spifi_attach 135 }; 136 137 int 138 spifi_match(parent, cf, aux) 139 struct device *parent; 140 struct cfdata *cf; 141 void *aux; 142 { 143 struct apbus_attach_args *apa = aux; 144 145 if (strcmp(apa->apa_name, "spifi") == 0) 146 return 1; 147 148 return 0; 149 } 150 151 void 152 spifi_attach(parent, self, aux) 153 struct device *parent, *self; 154 void *aux; 155 { 156 struct spifi_softc *sc = (void *)self; 157 struct apbus_attach_args *apa = aux; 158 struct device *dma; 159 int intr, i; 160 161 /* Initialize scbs. */ 162 TAILQ_INIT(&sc->free_scb); 163 TAILQ_INIT(&sc->ready_scb); 164 for (i = 0; i < sizeof(sc->sc_scb)/sizeof(sc->sc_scb[0]); i++) 165 TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain); 166 167 sc->sc_reg = (struct spifi_reg *)apa->apa_hwbase; 168 sc->sc_id = 7; /* XXX */ 169 170 /* Find my dmac3. */ 171 dma = dmac3_link(apa->apa_ctlnum); 172 if (dma == NULL) { 173 printf(": cannot find slave dmac\n"); 174 return; 175 } 176 sc->sc_dma = dma; 177 178 printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase); 179 printf(": SCSI ID = %d, using %s\n", sc->sc_id, dma->dv_xname); 180 181 dmac3_reset(sc->sc_dma); 182 183 DMAC3_SLOWACCESS(sc); 184 spifi_reset(sc); 185 DMAC3_FASTACCESS(sc); 186 187 sc->sc_adapter.adapt_dev = &sc->sc_dev; 188 sc->sc_adapter.adapt_nchannels = 1; 189 sc->sc_adapter.adapt_openings = 7; 190 sc->sc_adapter.adapt_max_periph = 1; 191 sc->sc_adapter.adapt_ioctl = NULL; 192 sc->sc_adapter.adapt_minphys = minphys; 193 sc->sc_adapter.adapt_request = spifi_scsipi_request; 194 195 memset(&sc->sc_channel, 0, sizeof(sc->sc_channel)); 196 sc->sc_channel.chan_adapter = &sc->sc_adapter; 197 sc->sc_channel.chan_bustype = &scsi_bustype; 198 sc->sc_channel.chan_channel = 0; 199 sc->sc_channel.chan_ntargets = 8; 200 sc->sc_channel.chan_nluns = 8; 201 sc->sc_channel.chan_id = sc->sc_id; 202 203 if (apa->apa_slotno == 0) 204 intr = NEWS5000_INT0_DMAC; 205 else 206 intr = SLOTTOMASK(apa->apa_slotno); 207 apbus_intr_establish(0, intr, 0, spifi_intr, sc, apa->apa_name, 208 apa->apa_ctlnum); 209 210 config_found(&sc->sc_dev, &sc->sc_channel, scsiprint); 211 } 212 213 void 214 spifi_scsipi_request(chan, req, arg) 215 struct scsipi_channel *chan; 216 scsipi_adapter_req_t req; 217 void *arg; 218 { 219 struct scsipi_xfer *xs; 220 struct scsipi_periph *periph; 221 struct spifi_softc *sc = (void *)chan->chan_adapter->adapt_dev; 222 struct spifi_scb *scb; 223 u_int flags; 224 int s; 225 226 switch (req) { 227 case ADAPTER_REQ_RUN_XFER: 228 xs = arg; 229 periph = xs->xs_periph; 230 231 DPRINTF("spifi_scsi_cmd\n"); 232 233 flags = xs->xs_control; 234 235 scb = spifi_get_scb(sc); 236 if (scb == NULL) { 237 panic("spifi_scsipi_request: no scb\n"); 238 } 239 240 scb->xs = xs; 241 scb->flags = 0; 242 scb->status = 0; 243 scb->daddr = (vaddr_t)xs->data; 244 scb->resid = xs->datalen; 245 bcopy(xs->cmd, &scb->cmd, xs->cmdlen); 246 scb->cmdlen = xs->cmdlen; 247 248 scb->target = periph->periph_target; 249 scb->lun = periph->periph_lun; 250 scb->lun_targ = scb->target | (scb->lun << 3); 251 252 if (flags & XS_CTL_DATA_IN) 253 scb->flags |= SPIFI_READ; 254 255 s = splbio(); 256 257 TAILQ_INSERT_TAIL(&sc->ready_scb, scb, chain); 258 259 if (sc->sc_nexus == NULL) /* IDLE */ 260 spifi_sched(sc); 261 262 splx(s); 263 264 if (flags & XS_CTL_POLL) { 265 if (spifi_poll(sc)) { 266 printf("spifi: timeout\n"); 267 if (spifi_poll(sc)) 268 printf("spifi: timeout again\n"); 269 } 270 } 271 return; 272 case ADAPTER_REQ_GROW_RESOURCES: 273 /* XXX Not supported. */ 274 return; 275 case ADAPTER_REQ_SET_XFER_MODE: 276 /* XXX Not supported. */ 277 return; 278 } 279 } 280 281 struct spifi_scb * 282 spifi_get_scb(sc) 283 struct spifi_softc *sc; 284 { 285 struct spifi_scb *scb; 286 int s; 287 288 s = splbio(); 289 scb = sc->free_scb.tqh_first; 290 if (scb) 291 TAILQ_REMOVE(&sc->free_scb, scb, chain); 292 splx(s); 293 294 return scb; 295 } 296 297 void 298 spifi_free_scb(sc, scb) 299 struct spifi_softc *sc; 300 struct spifi_scb *scb; 301 { 302 int s; 303 304 s = splbio(); 305 TAILQ_INSERT_HEAD(&sc->free_scb, scb, chain); 306 splx(s); 307 } 308 309 int 310 spifi_poll(sc) 311 struct spifi_softc *sc; 312 { 313 struct spifi_scb *scb = sc->sc_nexus; 314 struct scsipi_xfer *xs; 315 int count; 316 317 printf("spifi_poll: not implemented yet\n"); 318 delay(10000); 319 scb->status = SCSI_OK; 320 scb->resid = 0; 321 spifi_done(sc); 322 return 0; 323 324 if (xs == NULL) 325 return 0; 326 327 xs = scb->xs; 328 count = xs->timeout; 329 330 while (count > 0) { 331 if (dmac3_intr(sc->sc_dma) != 0) 332 spifi_intr(sc); 333 334 if (xs->xs_status & XS_STS_DONE) 335 return 0; 336 DELAY(1000); 337 count--; 338 }; 339 return 1; 340 } 341 342 void 343 spifi_minphys(bp) 344 struct buf *bp; 345 { 346 if (bp->b_bcount > 64*1024) 347 bp->b_bcount = 64*1024; 348 349 minphys(bp); 350 } 351 352 void 353 spifi_sched(sc) 354 struct spifi_softc *sc; 355 { 356 struct spifi_scb *scb; 357 358 scb = sc->ready_scb.tqh_first; 359 start: 360 if (scb == NULL || sc->sc_nexus != NULL) 361 return; 362 /* 363 if (sc->sc_targets[scb->target] & (1 << scb->lun)) 364 goto next; 365 */ 366 TAILQ_REMOVE(&sc->ready_scb, scb, chain); 367 368 #ifdef SPIFI_DEBUG 369 { 370 int i; 371 372 printf("spifi_sched: ID:LUN = %d:%d, ", scb->target, scb->lun); 373 printf("cmd = 0x%x", scb->cmd.opcode); 374 for (i = 0; i < 5; i++) 375 printf(" 0x%x", scb->cmd.bytes[i]); 376 printf("\n"); 377 } 378 #endif 379 380 DMAC3_SLOWACCESS(sc); 381 sc->sc_nexus = scb; 382 spifi_select(sc); 383 DMAC3_FASTACCESS(sc); 384 385 scb = scb->chain.tqe_next; 386 goto start; 387 } 388 389 static inline int 390 spifi_read_count(reg) 391 struct spifi_reg *reg; 392 { 393 int count; 394 395 count = (reg->count_hi & 0xff) << 16 | 396 (reg->count_mid & 0xff) << 8 | 397 (reg->count_low & 0xff); 398 return count; 399 } 400 401 static inline void 402 spifi_write_count(reg, count) 403 struct spifi_reg *reg; 404 int count; 405 { 406 reg->count_hi = count >> 16; 407 reg->count_mid = count >> 8; 408 reg->count_low = count; 409 } 410 411 412 #ifdef SPIFI_DEBUG 413 static char scsi_phase_name[][8] = { 414 "DATAOUT", "DATAIN", "COMMAND", "STATUS", 415 "", "", "MSGOUT", "MSGIN" 416 }; 417 #endif 418 419 int 420 spifi_intr(v) 421 void *v; 422 { 423 struct spifi_softc *sc = v; 424 struct spifi_reg *reg = sc->sc_reg; 425 int intr, state, icond; 426 struct spifi_scb *scb; 427 struct scsipi_xfer *xs; 428 #ifdef SPIFI_DEBUG 429 char bitmask[64]; 430 #endif 431 432 switch (dmac3_intr(sc->sc_dma)) { 433 case 0: 434 DPRINTF("spurious dma intr\n"); 435 return 0; 436 case -1: 437 printf("DMAC parity error, data PAD\n"); 438 439 DMAC3_SLOWACCESS(sc); 440 reg->prcmd = PRC_TRPAD; 441 DMAC3_FASTACCESS(sc); 442 return 1; 443 444 default: 445 break; 446 } 447 DMAC3_SLOWACCESS(sc); 448 449 intr = reg->intr & 0xff; 450 if (intr == 0) { 451 DMAC3_FASTACCESS(sc); 452 DPRINTF("spurious intr (not me)\n"); 453 return 0; 454 } 455 456 scb = sc->sc_nexus; 457 xs = scb->xs; 458 state = reg->spstat; 459 icond = reg->icond; 460 461 /* clear interrupt */ 462 reg->intr = ~intr; 463 464 #ifdef SPIFI_DEBUG 465 bitmask_snprintf(intr, INTR_BITMASK, bitmask, sizeof bitmask); 466 printf("spifi_intr intr = 0x%s (%s), ", bitmask, 467 scsi_phase_name[(reg->prstat >> 3) & 7]); 468 printf("state = 0x%x, icond = 0x%x\n", state, icond); 469 #endif 470 471 if (intr & INTR_FCOMP) { 472 spifi_fifo_drain(sc); 473 scb->status = reg->cmbuf[scb->target].status; 474 scb->resid = spifi_read_count(reg); 475 476 DPRINTF("datalen = %d, resid = %d, status = 0x%x\n", 477 xs->datalen, scb->resid, scb->status); 478 DPRINTF("msg = 0x%x\n", reg->cmbuf[sc->sc_id].cdb[0]); 479 480 DMAC3_FASTACCESS(sc); 481 spifi_done(sc); 482 return 1; 483 } 484 if (intr & INTR_DISCON) 485 panic("disconnect"); 486 487 if (intr & INTR_TIMEO) { 488 xs->error = XS_SELTIMEOUT; 489 DMAC3_FASTACCESS(sc); 490 spifi_done(sc); 491 return 1; 492 } 493 if (intr & INTR_BSRQ) { 494 if (scb == NULL) 495 panic("reconnect?"); 496 497 if (intr & INTR_PERR) { 498 printf("%s: %d:%d parity error\n", sc->sc_dev.dv_xname, 499 scb->target, scb->lun); 500 501 /* XXX reset */ 502 xs->error = XS_DRIVER_STUFFUP; 503 spifi_done(sc); 504 return 1; 505 } 506 507 if (state >> 4 == SPS_MSGIN && icond == ICOND_NXTREQ) 508 panic("spifi_intr: NXTREQ"); 509 if (reg->fifoctrl & FIFOC_RQOVRN) 510 panic("spifi_intr RQOVRN"); 511 if (icond == ICOND_UXPHASEZ) 512 panic("ICOND_UXPHASEZ"); 513 514 if ((icond & 0x0f) == ICOND_ADATAOFF) { 515 spifi_data_io(sc); 516 goto done; 517 } 518 if ((icond & 0xf0) == ICOND_UBF) { 519 reg->exstat = reg->exstat & ~EXS_UBF; 520 spifi_pmatch(sc); 521 goto done; 522 } 523 524 /* 525 * XXX Work around the SPIFI bug that interrupts during 526 * XXX dataout phase. 527 */ 528 if (state == ((SPS_DATAOUT << 4) | SPS_INTR) && 529 (reg->prstat & PRS_PHASE) == SPIFI_DATAOUT) { 530 reg->prcmd = PRC_DATAOUT; 531 goto done; 532 } 533 if ((reg->prstat & PRS_Z) == 0) { 534 spifi_pmatch(sc); 535 goto done; 536 } 537 538 panic("spifi_intr: unknown intr state"); 539 } 540 541 done: 542 DMAC3_FASTACCESS(sc); 543 return 1; 544 } 545 546 void 547 spifi_pmatch(sc) 548 struct spifi_softc *sc; 549 { 550 struct spifi_reg *reg = sc->sc_reg; 551 int phase; 552 553 phase = (reg->prstat & PRS_PHASE); 554 555 #ifdef SPIFI_DEBUG 556 printf("spifi_pmatch (%s)\n", scsi_phase_name[phase >> 3]); 557 #endif 558 559 switch (phase) { 560 561 case SPIFI_COMMAND: 562 spifi_command(sc); 563 break; 564 case SPIFI_DATAIN: 565 case SPIFI_DATAOUT: 566 spifi_data_io(sc); 567 break; 568 case SPIFI_STATUS: 569 spifi_status(sc); 570 break; 571 572 case SPIFI_MSGIN: /* XXX */ 573 case SPIFI_MSGOUT: /* XXX */ 574 default: 575 printf("spifi: unknown phase %d\n", phase); 576 } 577 } 578 579 void 580 spifi_select(sc) 581 struct spifi_softc *sc; 582 { 583 struct spifi_reg *reg = sc->sc_reg; 584 struct spifi_scb *scb = sc->sc_nexus; 585 int sel; 586 587 #if 0 588 if (reg->loopdata || reg->intr) 589 return; 590 #endif 591 592 if (scb == NULL) { 593 printf("%s: spifi_select: NULL nexus\n", sc->sc_dev.dv_xname); 594 return; 595 } 596 597 reg->exctrl = EXC_IPLOCK; 598 599 dmac3_reset(sc->sc_dma); 600 sel = scb->target << 4 | SEL_ISTART | SEL_IRESELEN | SEL_WATN; 601 spifi_sendmsg(sc, SEND_IDENTIFY); 602 reg->select = sel; 603 } 604 605 void 606 spifi_sendmsg(sc, msg) 607 struct spifi_softc *sc; 608 int msg; 609 { 610 struct spifi_scb *scb = sc->sc_nexus; 611 /* struct mesh_tinfo *ti; */ 612 int lun, len, i; 613 614 int id = sc->sc_id; 615 struct spifi_reg *reg = sc->sc_reg; 616 617 DPRINTF("spifi_sendmsg: sending"); 618 sc->sc_msgout = msg; 619 len = 0; 620 621 if (msg & SEND_REJECT) { 622 DPRINTF(" REJECT"); 623 sc->sc_omsg[len++] = MSG_MESSAGE_REJECT; 624 } 625 if (msg & SEND_IDENTIFY) { 626 DPRINTF(" IDENTIFY"); 627 lun = scb->xs->xs_periph->periph_lun; 628 sc->sc_omsg[len++] = MSG_IDENTIFY(lun, 0); 629 } 630 if (msg & SEND_SDTR) { 631 DPRINTF(" SDTR"); 632 #if 0 633 ti = &sc->sc_tinfo[scb->target]; 634 sc->sc_omsg[len++] = MSG_EXTENDED; 635 sc->sc_omsg[len++] = 3; 636 sc->sc_omsg[len++] = MSG_EXT_SDTR; 637 sc->sc_omsg[len++] = ti->period; 638 sc->sc_omsg[len++] = ti->offset; 639 #endif 640 } 641 DPRINTF("\n"); 642 643 reg->cmlen = CML_AMSG_EN | len; 644 for (i = 0; i < len; i++) 645 reg->cmbuf[id].cdb[i] = sc->sc_omsg[i]; 646 } 647 void 648 spifi_command(struct spifi_softc *sc) 649 { 650 struct spifi_scb *scb = sc->sc_nexus; 651 struct spifi_reg *reg = sc->sc_reg; 652 int len = scb->cmdlen; 653 u_char *cmdp = (char *)&scb->cmd; 654 int i; 655 656 DPRINTF("spifi_command\n"); 657 658 reg->cmdpage = scb->lun_targ; 659 660 if (reg->init_status & IST_ACK) { 661 /* Negate ACK. */ 662 reg->prcmd = PRC_NJMP | PRC_CLRACK | PRC_COMMAND; 663 reg->prcmd = PRC_NJMP | PRC_COMMAND; 664 } 665 666 reg->cmlen = CML_AMSG_EN | len; 667 668 for (i = 0; i < len; i++) 669 reg->cmbuf[sc->sc_id].cdb[i] = *cmdp++; 670 671 reg->prcmd = PRC_COMMAND; 672 } 673 674 void 675 spifi_data_io(struct spifi_softc *sc) 676 { 677 struct spifi_scb *scb = sc->sc_nexus; 678 struct spifi_reg *reg = sc->sc_reg; 679 int phase; 680 681 DPRINTF("spifi_data_io\n"); 682 683 phase = reg->prstat & PRS_PHASE; 684 dmac3_reset(sc->sc_dma); 685 686 spifi_write_count(reg, scb->resid); 687 reg->cmlen = CML_AMSG_EN | 1; 688 reg->data_xfer = 0; 689 690 scb->flags |= SPIFI_DMA; 691 if (phase == SPIFI_DATAIN) { 692 if (reg->fifoctrl & FIFOC_SSTKACT) { 693 /* 694 * Clear FIFO and load the contents of synchronous 695 * stack into the FIFO. 696 */ 697 reg->fifoctrl = FIFOC_CLREVEN; 698 reg->fifoctrl = FIFOC_LOAD; 699 } 700 reg->autodata = ADATA_IN | scb->lun_targ; 701 dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_RECV); 702 reg->prcmd = PRC_DATAIN; 703 } else { 704 reg->fifoctrl = FIFOC_CLREVEN; 705 reg->autodata = scb->lun_targ; 706 dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_SEND); 707 reg->prcmd = PRC_DATAOUT; 708 } 709 } 710 711 void 712 spifi_status(struct spifi_softc *sc) 713 { 714 struct spifi_reg *reg = sc->sc_reg; 715 716 DPRINTF("spifi_status\n"); 717 spifi_fifo_drain(sc); 718 reg->cmlen = CML_AMSG_EN | 1; 719 reg->prcmd = PRC_STATUS; 720 } 721 722 int 723 spifi_done(sc) 724 struct spifi_softc *sc; 725 { 726 struct spifi_scb *scb = sc->sc_nexus; 727 struct scsipi_xfer *xs = scb->xs; 728 729 DPRINTF("spifi_done\n"); 730 731 xs->status = scb->status; 732 if (xs->status == SCSI_CHECK) { 733 DPRINTF("spifi_done: CHECK CONDITION\n"); 734 if (xs->error == XS_NOERROR) 735 xs->error = XS_BUSY; 736 } 737 738 xs->resid = scb->resid; 739 740 scsipi_done(xs); 741 spifi_free_scb(sc, scb); 742 743 sc->sc_nexus = NULL; 744 spifi_sched(sc); 745 746 return FALSE; 747 } 748 749 void 750 spifi_fifo_drain(sc) 751 struct spifi_softc *sc; 752 { 753 struct spifi_scb *scb = sc->sc_nexus; 754 struct spifi_reg *reg = sc->sc_reg; 755 int fifoctrl, fifo_count; 756 757 DPRINTF("spifi_fifo_drain\n"); 758 759 if ((scb->flags & SPIFI_READ) == 0) 760 return; 761 762 fifoctrl = reg->fifoctrl; 763 if (fifoctrl & FIFOC_SSTKACT) 764 return; 765 766 fifo_count = 8 - (fifoctrl & FIFOC_FSLOT); 767 if (fifo_count > 0 && (scb->flags & SPIFI_DMA)) { 768 /* Flush data still in FIFO. */ 769 reg->fifoctrl = FIFOC_FLUSH; 770 return; 771 } 772 773 reg->fifoctrl = FIFOC_CLREVEN; 774 } 775 776 void 777 spifi_reset(sc) 778 struct spifi_softc *sc; 779 { 780 struct spifi_reg *reg = sc->sc_reg; 781 int id = sc->sc_id; 782 783 DPRINTF("spifi_reset\n"); 784 785 reg->auxctrl = AUXCTRL_SRST; 786 reg->auxctrl = AUXCTRL_CRST; 787 788 dmac3_reset(sc->sc_dma); 789 790 reg->auxctrl = AUXCTRL_SRST; 791 reg->auxctrl = AUXCTRL_CRST; 792 reg->auxctrl = AUXCTRL_DMAEDGE; 793 794 /* Mask (only) target mode interrupts. */ 795 reg->imask = INTR_TGSEL | INTR_COMRECV; 796 797 reg->config = CONFIG_DMABURST | CONFIG_PCHKEN | CONFIG_PGENEN | id; 798 reg->fastwide = FAST_FASTEN; 799 reg->prctrl = 0; 800 reg->loopctrl = 0; 801 802 /* Enable automatic status input except the initiator. */ 803 reg->autostat = ~(1 << id); 804 805 reg->fifoctrl = FIFOC_CLREVEN; 806 spifi_write_count(reg, 0); 807 808 /* Flush write buffer. */ 809 (void)reg->spstat; 810 } 811 812 void 813 spifi_bus_reset(sc) 814 struct spifi_softc *sc; 815 { 816 struct spifi_reg *reg = sc->sc_reg; 817 818 printf("%s: bus reset\n", sc->sc_dev.dv_xname); 819 820 sc->sc_nexus = NULL; 821 822 reg->auxctrl = AUXCTRL_SETRST; 823 delay(100); 824 reg->auxctrl = 0; 825 } 826 827 #if 0 828 static u_char spifi_sync_period[] = { 829 /* 0 1 2 3 4 5 6 7 8 9 10 11 */ 830 137, 125, 112, 100, 87, 75, 62, 50, 43, 37, 31, 25 831 }; 832 833 void 834 spifi_setsync(sc, ti) 835 struct spifi_softc *sc; 836 struct spifi_tinfo *ti; 837 { 838 if ((ti->flags & T_SYNCMODE) == 0) 839 reg->data_xfer = 0; 840 else { 841 int period = ti->period; 842 int offset = ti->offset; 843 int v; 844 845 for (v = sizeof(spifi_sync_period) - 1; v >= 0; v--) 846 if (spifi_sync_period[v] >= period) 847 break; 848 if (v == -1) 849 reg->data_xfer = 0; /* XXX */ 850 else 851 reg->data_xfer = v << 4 | offset; 852 } 853 } 854 #endif 855