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