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