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