Home | History | Annotate | Line # | Download | only in boot
scsi.c revision 1.10.122.1
      1  1.10.122.1    martin /*      $NetBSD: scsi.c,v 1.10.122.1 2023/02/12 12:18:24 martin Exp $        */
      2         1.1       dbj /*
      3         1.1       dbj  * Copyright (c) 1994, 1997 Rolf Grossmann
      4         1.1       dbj  * All rights reserved.
      5         1.1       dbj  *
      6         1.1       dbj  * Redistribution and use in source and binary forms, with or without
      7         1.1       dbj  * modification, are permitted provided that the following conditions
      8         1.1       dbj  * are met:
      9         1.1       dbj  * 1. Redistributions of source code must retain the above copyright
     10         1.1       dbj  *    notice, this list of conditions and the following disclaimer.
     11         1.1       dbj  * 2. Redistributions in binary form must reproduce the above copyright
     12         1.1       dbj  *    notice, this list of conditions and the following disclaimer in the
     13         1.1       dbj  *    documentation and/or other materials provided with the distribution.
     14         1.1       dbj  * 3. All advertising materials mentioning features or use of this software
     15         1.1       dbj  *    must display the following acknowledgement:
     16         1.1       dbj  *      This product includes software developed by Rolf Grossmann.
     17         1.1       dbj  * 4. The name of the author may not be used to endorse or promote products
     18         1.1       dbj  *    derived from this software without specific prior written permission
     19         1.1       dbj  *
     20         1.1       dbj  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21         1.1       dbj  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22         1.1       dbj  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23         1.1       dbj  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24         1.1       dbj  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25         1.1       dbj  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26         1.1       dbj  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27         1.1       dbj  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28         1.1       dbj  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29         1.1       dbj  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30         1.1       dbj  */
     31         1.1       dbj 
     32         1.1       dbj #include <sys/param.h>
     33         1.1       dbj #include <next68k/dev/espreg.h>
     34         1.3  jdolecek #include <dev/ic/ncr53c9xreg.h>
     35         1.1       dbj #include <dev/scsipi/scsi_message.h>
     36         1.1       dbj #if 0
     37         1.1       dbj #include <next/next/prominfo.h>
     38         1.1       dbj #else
     39         1.1       dbj #include <next68k/next68k/nextrom.h>
     40         1.1       dbj #endif
     41         1.1       dbj #include "scsireg.h"
     42         1.1       dbj #include "dmareg.h"
     43         1.1       dbj #include "scsivar.h"
     44         1.1       dbj 
     45         1.1       dbj #include <lib/libsa/stand.h>
     46         1.1       dbj 
     47         1.1       dbj struct  scsi_softc scsi_softc, *sc = &scsi_softc;
     48         1.1       dbj char the_dma_buffer[MAX_DMASIZE+DMA_ENDALIGNMENT], *dma_buffer;
     49         1.1       dbj 
     50         1.1       dbj int scsi_msgin(void);
     51         1.1       dbj int dma_start(char *addr, int len);
     52         1.1       dbj int dma_done(void);
     53         1.1       dbj 
     54         1.2       dbj void scsi_init(void);
     55         1.2       dbj void scsierror(char *error);
     56         1.9        he short scsi_getbyte(volatile uint8_t *sr);
     57         1.2       dbj int scsi_wait_for_intr(void);
     58         1.2       dbj int scsiicmd(char target, char lun,
     59         1.4  christos 	 u_char *cbuf, int clen, char *addr, int *len);
     60         1.2       dbj 
     61         1.4  christos #define NDPRINTF(x)
     62         1.4  christos #define PRINTF(x)
     63         1.4  christos /* printf x; */
     64  1.10.122.1    martin #ifdef SCSI_DEBUG
     65         1.1       dbj #define DPRINTF(x) printf x;
     66         1.1       dbj #else
     67         1.1       dbj #define DPRINTF(x)
     68         1.1       dbj #endif
     69         1.1       dbj 
     70         1.1       dbj void
     71         1.1       dbj scsi_init(void)
     72         1.1       dbj {
     73         1.9        he     volatile uint8_t *sr;
     74         1.1       dbj     struct dma_dev *dma;
     75         1.1       dbj 
     76         1.1       dbj     sr = P_SCSI;
     77         1.1       dbj     dma = (struct dma_dev *)P_SCSI_CSR;
     78         1.1       dbj 
     79         1.1       dbj     dma_buffer = DMA_ALIGN(char *, the_dma_buffer);
     80  1.10.122.1    martin 
     81         1.1       dbj     P_FLOPPY[FLP_CTRL] &= ~FLC_82077_SEL;	/* select SCSI chip */
     82         1.1       dbj 
     83         1.6       wiz     /* first reset DMA */
     84         1.1       dbj     dma->dd_csr        = DMACSR_RESET;
     85         1.1       dbj     DELAY(200);
     86         1.1       dbj     sr[ESP_DCTL]       = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_RESET;
     87         1.1       dbj     DELAY(10);
     88         1.1       dbj     sr[ESP_DCTL]       = ESPDCTL_20MHZ | ESPDCTL_INTENB;
     89         1.1       dbj     DELAY(10);
     90         1.1       dbj 
     91         1.1       dbj     /* then reset the SCSI chip */
     92         1.3  jdolecek     sr[NCR_CMD]        = NCRCMD_RSTCHIP;
     93         1.3  jdolecek     sr[NCR_CMD]        = NCRCMD_NOP;
     94         1.1       dbj     DELAY(500);
     95         1.1       dbj 
     96         1.1       dbj     /* now reset the SCSI bus */
     97         1.3  jdolecek     sr[NCR_CMD]        = NCRCMD_RSTSCSI;
     98         1.4  christos     DELAY(4000000);	/* XXX should be about 2-3 seconds at least */
     99  1.10.122.1    martin 
    100         1.1       dbj     /* then reset the SCSI chip again and initialize it properly */
    101         1.3  jdolecek     sr[NCR_CMD]        = NCRCMD_RSTCHIP;
    102         1.3  jdolecek     sr[NCR_CMD]        = NCRCMD_NOP;
    103         1.1       dbj     DELAY(500);
    104         1.3  jdolecek     sr[NCR_CFG1]       = NCRCFG1_SLOW | NCRCFG1_BUSID;
    105         1.3  jdolecek     sr[NCR_CFG2]       = 0;
    106         1.3  jdolecek     sr[NCR_CCF]        = 4; /* S5RCLKCONV_FACTOR(20); */
    107         1.3  jdolecek     sr[NCR_TIMEOUT]    = 152; /* S5RSELECT_TIMEOUT(20,250); */
    108         1.3  jdolecek     sr[NCR_SYNCOFF]    = 0;
    109         1.3  jdolecek     sr[NCR_SYNCTP]     = 5;
    110         1.1       dbj    /*
    111         1.1       dbj     sc->sc_intrstatus  = sr->s5r_intrstatus;
    112         1.1       dbj     sc->sc_intrstatus  = sr->s5r_intrstatus;
    113         1.1       dbj     */
    114         1.3  jdolecek     sr[NCR_CFG1]       = NCRCFG1_PARENB | NCRCFG1_BUSID;
    115         1.1       dbj 
    116         1.1       dbj     sc->sc_state       = SCSI_IDLE;
    117         1.1       dbj }
    118         1.1       dbj 
    119         1.1       dbj void
    120         1.1       dbj scsierror(char *error)
    121         1.1       dbj {
    122         1.1       dbj     printf("scsierror: %s.\n", error);
    123         1.1       dbj }
    124         1.1       dbj 
    125         1.1       dbj short
    126         1.9        he scsi_getbyte(volatile uint8_t *sr)
    127         1.1       dbj {
    128  1.10.122.1    martin     if ((sr[NCR_FFLAG] & NCRFIFO_FF) == 0)
    129         1.1       dbj     {
    130         1.1       dbj 	printf("getbyte: no data!\n");
    131         1.1       dbj 	return -1;
    132         1.1       dbj     }
    133         1.3  jdolecek     return sr[NCR_FIFO];
    134         1.1       dbj }
    135         1.1       dbj 
    136         1.1       dbj int
    137         1.1       dbj scsi_wait_for_intr(void)
    138         1.1       dbj {
    139         1.1       dbj #if 0
    140         1.1       dbj   extern struct prominfo *pi;
    141         1.1       dbj   volitle int = pi->pi_intrstat; /* ### use constant? */
    142         1.1       dbj #else
    143         1.1       dbj   extern char *mg;
    144         1.1       dbj #define	MON(type, off) (*(type *)((u_int) (mg) + off))
    145         1.1       dbj   volatile int *intrstat = MON(volatile int *,MG_intrstat);
    146         1.4  christos #ifdef SCSI_DEBUG
    147         1.4  christos /*   volatile int *intrmask = MON(volatile int *,MG_intrmask); */
    148         1.4  christos #endif
    149         1.1       dbj #endif
    150         1.1       dbj     int count;
    151         1.1       dbj 
    152         1.2       dbj     for(count = 0; count < SCSI_TIMEOUT; count++) {
    153         1.4  christos 			NDPRINTF(("  *intrstat = 0x%x\t*intrmask = 0x%x\n",*intrstat,*intrmask));
    154         1.2       dbj 
    155         1.1       dbj 	if (*intrstat & SCSI_INTR)
    156         1.1       dbj 	    return 0;
    157         1.2       dbj 		}
    158         1.1       dbj 
    159         1.1       dbj     printf("scsiicmd: timed out.\n");
    160         1.1       dbj     return -1;
    161         1.1       dbj }
    162         1.1       dbj 
    163         1.1       dbj int
    164         1.1       dbj scsiicmd(char target, char lun,
    165         1.1       dbj 	 u_char *cbuf, int clen,
    166         1.4  christos 	 char *addr, int *len)
    167         1.1       dbj {
    168         1.9        he     volatile uint8_t *sr;
    169         1.1       dbj     int i;
    170         1.1       dbj 
    171         1.1       dbj     DPRINTF(("scsiicmd: [%x, %d] -> %d (%lx, %d)\n",*cbuf, clen,
    172         1.4  christos 	     target, (long)addr, *len));
    173         1.1       dbj     sr = P_SCSI;
    174         1.1       dbj 
    175         1.1       dbj     if (sc->sc_state != SCSI_IDLE) {
    176         1.1       dbj         scsierror("scsiiscmd: bad state");
    177         1.1       dbj 	return EIO;
    178         1.1       dbj     }
    179         1.1       dbj     sc->sc_result = 0;
    180         1.1       dbj 
    181         1.1       dbj     /* select target */
    182         1.3  jdolecek     sr[NCR_CMD]   = NCRCMD_FLUSH;
    183         1.1       dbj     DELAY(10);
    184         1.3  jdolecek     sr[NCR_SELID] = target;
    185         1.3  jdolecek     sr[NCR_FIFO]  = MSG_IDENTIFY(lun, 0);
    186         1.1       dbj     for (i=0; i<clen; i++)
    187         1.3  jdolecek 	sr[NCR_FIFO] = cbuf[i];
    188         1.3  jdolecek     sr[NCR_CMD]   = NCRCMD_SELATN;
    189         1.1       dbj     sc->sc_state  = SCSI_SELECTING;
    190  1.10.122.1    martin 
    191         1.1       dbj     while(sc->sc_state != SCSI_DONE) {
    192         1.1       dbj 	if (scsi_wait_for_intr()) /* maybe we'd better use real intrs ? */
    193         1.1       dbj 	    return EIO;
    194         1.1       dbj 
    195         1.1       dbj 	if (sc->sc_state == SCSI_DMA)
    196         1.1       dbj 	{
    197         1.6       wiz 	    /* registers are not valid on DMA intr */
    198         1.1       dbj 	    sc->sc_status = sc->sc_seqstep = sc->sc_intrstatus = 0;
    199         1.6       wiz 	    DPRINTF(("scsiicmd: DMA intr\n"));
    200         1.4  christos 	    sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMARD;
    201         1.1       dbj 	}
    202         1.4  christos 
    203         1.4  christos 	/* scsi processing */
    204         1.4  christos 	sc->sc_status     = sr[NCR_STAT];
    205         1.4  christos 	sc->sc_seqstep    = sr[NCR_STEP];
    206         1.4  christos 	sc->sc_intrstatus = sr[NCR_INTR];
    207         1.4  christos     redo:
    208         1.4  christos 	DPRINTF(("scsiicmd: regs[intr=%x, stat=%x, step=%x]\n",
    209         1.4  christos 		 sc->sc_intrstatus, sc->sc_status, sc->sc_seqstep));
    210  1.10.122.1    martin 
    211         1.3  jdolecek 	if (sc->sc_intrstatus & NCRINTR_SBR) {
    212         1.1       dbj 	    scsierror("scsi bus reset");
    213         1.1       dbj 	    return EIO;
    214         1.1       dbj 	}
    215  1.10.122.1    martin 
    216         1.3  jdolecek 	if ((sc->sc_status & NCRSTAT_GE)
    217         1.3  jdolecek 	    || (sc->sc_intrstatus & NCRINTR_ILL)) {
    218         1.1       dbj 	    scsierror("software error");
    219         1.1       dbj 	    return EIO;
    220         1.1       dbj 	}
    221         1.3  jdolecek 	if (sc->sc_status & NCRSTAT_PE)
    222         1.1       dbj 	{
    223         1.1       dbj 	    scsierror("parity error");
    224         1.1       dbj 	    return EIO;
    225         1.1       dbj 	}
    226         1.1       dbj 
    227         1.1       dbj 	switch(sc->sc_state)
    228         1.1       dbj 	{
    229         1.1       dbj 	  case SCSI_SELECTING:
    230  1.10.122.1    martin 	      if (sc->sc_intrstatus & NCRINTR_DIS)
    231         1.1       dbj 	      {
    232         1.1       dbj 		  sc->sc_state = SCSI_IDLE;
    233         1.1       dbj 		  return EUNIT;	/* device not present */
    234         1.1       dbj 	      }
    235  1.10.122.1    martin 
    236         1.3  jdolecek #define NCRINTR_DONE (NCRINTR_BS | NCRINTR_FC)
    237         1.3  jdolecek 	      if ((sc->sc_intrstatus & NCRINTR_DONE) != NCRINTR_DONE)
    238         1.1       dbj 	      {
    239         1.1       dbj 		  scsierror("selection failed");
    240         1.1       dbj 		  return EIO;
    241         1.1       dbj 	      }
    242         1.1       dbj 	      sc->sc_state = SCSI_HASBUS;
    243         1.1       dbj 	      break;
    244         1.1       dbj 	  case SCSI_HASBUS:
    245         1.3  jdolecek 	      if (sc->sc_intrstatus & NCRINTR_DIS)
    246         1.1       dbj 	      {
    247         1.1       dbj 		  scsierror("target disconnected");
    248         1.1       dbj 		  return EIO;
    249         1.1       dbj 	      }
    250         1.1       dbj 	      break;
    251         1.1       dbj 	  case SCSI_DMA:
    252         1.3  jdolecek 	      if (sc->sc_intrstatus & NCRINTR_DIS)
    253         1.1       dbj 	      {
    254         1.1       dbj 		  scsierror("target disconnected");
    255         1.1       dbj 		  return EIO;
    256         1.1       dbj 	      }
    257         1.4  christos 	      *len = dma_done();
    258         1.4  christos 	      if (*len < 0) {
    259         1.4  christos 		      *len = 0;
    260         1.4  christos 		      return EIO;
    261         1.4  christos 	      }
    262         1.4  christos 	      /* continue; */
    263         1.4  christos 	      sc->sc_status     = sr[NCR_STAT];
    264         1.4  christos 	      goto redo;
    265         1.4  christos 	      break;
    266         1.1       dbj 	  case SCSI_CLEANUP:
    267         1.3  jdolecek 	      if (sc->sc_intrstatus & NCRINTR_DIS)
    268         1.1       dbj 	      {
    269         1.1       dbj 		  sc->sc_state = SCSI_DONE;
    270         1.1       dbj 		  continue;
    271         1.1       dbj 	      }
    272         1.1       dbj 	      DPRINTF(("hmm ... no disconnect on cleanup?\n"));
    273         1.1       dbj 	      sc->sc_state = SCSI_DONE;	/* maybe ... */
    274         1.1       dbj 	      break;
    275         1.1       dbj 	}
    276         1.1       dbj 
    277         1.1       dbj 	/* transfer information now */
    278         1.3  jdolecek 	switch(sc->sc_status & NCRSTAT_PHASE)
    279         1.1       dbj 	{
    280         1.1       dbj 	  case DATA_IN_PHASE:
    281         1.4  christos 		  sr[NCR_CMD] = NCRCMD_FLUSH;
    282         1.4  christos 	      if (dma_start(addr, *len) != 0)
    283         1.1       dbj 		  return EIO;
    284         1.1       dbj 	      break;
    285         1.1       dbj 	  case DATA_OUT_PHASE:
    286         1.1       dbj 	      scsierror("data out phase not implemented");
    287         1.1       dbj 	      return EIO;
    288         1.1       dbj 	  case STATUS_PHASE:
    289         1.1       dbj 	      DPRINTF(("status phase: "));
    290         1.3  jdolecek 	      sr[NCR_CMD] = NCRCMD_ICCS;
    291         1.1       dbj 	      sc->sc_result = scsi_getbyte(sr);
    292         1.1       dbj 	      DPRINTF(("status is 0x%x.\n", sc->sc_result));
    293         1.1       dbj 	      break;
    294         1.1       dbj 	  case MSG_IN_PHASE:
    295         1.4  christos 		if ((sc->sc_intrstatus & NCRINTR_BS) != 0) {
    296         1.4  christos 			sr[NCR_CMD] = NCRCMD_FLUSH;
    297         1.4  christos 			sr[NCR_CMD] = NCRCMD_TRANS;
    298         1.4  christos 		} else
    299         1.4  christos 			if (scsi_msgin() != 0)
    300         1.4  christos 				return EIO;
    301         1.4  christos 		break;
    302         1.1       dbj 	  default:
    303         1.1       dbj 	      DPRINTF(("phase not implemented: 0x%x.\n",
    304         1.3  jdolecek 		      sc->sc_status & NCRSTAT_PHASE));
    305         1.1       dbj               scsierror("bad phase");
    306         1.1       dbj 	      return EIO;
    307         1.1       dbj 	}
    308         1.1       dbj     }
    309         1.1       dbj 
    310         1.1       dbj     sc->sc_state = SCSI_IDLE;
    311         1.1       dbj     return -sc->sc_result;
    312         1.1       dbj }
    313  1.10.122.1    martin 
    314         1.1       dbj int
    315         1.1       dbj scsi_msgin(void)
    316         1.1       dbj {
    317         1.9        he     volatile uint8_t *sr;
    318         1.1       dbj     u_char msg;
    319         1.1       dbj 
    320         1.1       dbj     sr = P_SCSI;
    321         1.1       dbj 
    322         1.1       dbj     msg = scsi_getbyte(sr);
    323         1.1       dbj     if (msg)
    324         1.1       dbj     {
    325         1.1       dbj 	printf("unexpected msg: 0x%x.\n",msg);
    326         1.1       dbj 	return -1;
    327         1.1       dbj     }
    328         1.3  jdolecek     if ((sc->sc_intrstatus & NCRINTR_FC) == 0)
    329         1.1       dbj     {
    330         1.1       dbj 	printf("not function complete.\n");
    331         1.1       dbj 	return -1;
    332         1.1       dbj     }
    333         1.1       dbj     sc->sc_state = SCSI_CLEANUP;
    334         1.3  jdolecek     sr[NCR_CMD]  = NCRCMD_MSGOK;
    335         1.1       dbj     return 0;
    336         1.1       dbj }
    337         1.1       dbj 
    338         1.1       dbj int
    339         1.1       dbj dma_start(char *addr, int len)
    340         1.1       dbj {
    341         1.9        he     volatile uint8_t *sr;
    342         1.1       dbj     struct dma_dev *dma;
    343  1.10.122.1    martin 
    344         1.1       dbj     sr = P_SCSI;
    345         1.1       dbj     dma = (struct dma_dev *)P_SCSI_CSR;
    346  1.10.122.1    martin 
    347         1.1       dbj     if (len > MAX_DMASIZE)
    348         1.1       dbj     {
    349         1.6       wiz 	scsierror("DMA too long");
    350         1.1       dbj 	return -1;
    351         1.1       dbj     }
    352         1.1       dbj 
    353         1.1       dbj     if (addr == NULL || len == 0)
    354         1.1       dbj     {
    355         1.1       dbj #if 0 /* I'd take that as an error in my code */
    356         1.6       wiz 	DPRINTF(("hmm ... no DMA requested.\n"));
    357         1.3  jdolecek 	sr[NCR_TCL] = 0;
    358         1.3  jdolecek 	sr[NCR_TCM] = 1;
    359         1.3  jdolecek 	sr[NCR_CMD] = NCRCMD_NOP;
    360         1.3  jdolecek 	sr[NCR_CMD] = NCRCMD_DMA | NCRCMD_TRPAD;
    361         1.1       dbj 	return 0;
    362         1.1       dbj #else
    363         1.6       wiz 	scsierror("unrequested DMA");
    364         1.1       dbj 	return -1;
    365         1.1       dbj #endif
    366         1.1       dbj     }
    367  1.10.122.1    martin 
    368         1.6       wiz     PRINTF(("DMA start: %lx, %d byte.\n", (long)addr, len));
    369         1.2       dbj 
    370  1.10.122.1    martin     DPRINTF(("dma_bufffer: start: 0x%lx end: 0x%lx \n",
    371         1.2       dbj 				(long)dma_buffer,(long)DMA_ENDALIGN(char *, dma_buffer+len)));
    372         1.2       dbj 
    373         1.1       dbj     sc->dma_addr = addr;
    374         1.1       dbj     sc->dma_len = len;
    375  1.10.122.1    martin 
    376         1.3  jdolecek     sr[NCR_TCL]  = len & 0xff;
    377         1.3  jdolecek     sr[NCR_TCM]  = len >> 8;
    378         1.3  jdolecek     sr[NCR_CMD]  = NCRCMD_DMA | NCRCMD_NOP;
    379         1.3  jdolecek     sr[NCR_CMD]  = NCRCMD_DMA | NCRCMD_TRANS;
    380         1.2       dbj 
    381         1.2       dbj #if 0
    382         1.1       dbj     dma->dd_csr = DMACSR_READ | DMACSR_RESET;
    383         1.1       dbj     dma->dd_next_initbuf = dma_buffer;
    384         1.1       dbj     dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
    385         1.1       dbj     dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
    386         1.2       dbj #else
    387         1.2       dbj     dma->dd_csr = 0;
    388         1.2       dbj     dma->dd_csr = DMACSR_INITBUF | DMACSR_READ | DMACSR_RESET;
    389         1.4  christos     dma->dd_next = dma_buffer;
    390         1.2       dbj     dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
    391         1.2       dbj     dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
    392         1.2       dbj #endif
    393         1.2       dbj 
    394         1.1       dbj     sr[ESP_DCTL] = ESPDCTL_20MHZ|ESPDCTL_INTENB|ESPDCTL_DMAMOD|ESPDCTL_DMARD;
    395         1.1       dbj 
    396         1.1       dbj     sc->sc_state = SCSI_DMA;
    397         1.1       dbj     return 0;
    398         1.1       dbj }
    399         1.1       dbj 
    400         1.1       dbj int
    401         1.1       dbj dma_done(void)
    402         1.1       dbj {
    403         1.9        he     volatile uint8_t *sr;
    404         1.1       dbj     struct dma_dev *dma;
    405         1.4  christos     int resid, state;
    406         1.4  christos     int flushcount = 0;
    407  1.10.122.1    martin 
    408         1.1       dbj     sr = P_SCSI;
    409         1.1       dbj     dma = (struct dma_dev *)P_SCSI_CSR;
    410         1.1       dbj 
    411         1.1       dbj     state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE
    412         1.1       dbj 			   | DMACSR_SUPDATE | DMACSR_ENABLE);
    413         1.1       dbj 
    414         1.4  christos     sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMARD;
    415         1.4  christos     resid = sr[NCR_TCM]<<8 | sr[NCR_TCL];
    416         1.6       wiz     DPRINTF(("DMA state = 0x%x, remain = %d.\n", state, resid));
    417         1.4  christos 
    418         1.4  christos     if (!(sr[NCR_FFLAG] & NCRFIFO_FF)) {
    419         1.4  christos 	    sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
    420         1.4  christos 		    | ESPDCTL_DMARD;
    421  1.10.122.1    martin 	    while (!(state & DMACSR_COMPLETE) && (state & DMACSR_ENABLE) && flushcount < 16)
    422         1.4  christos 	    {
    423  1.10.122.1    martin 
    424         1.6       wiz 		    DPRINTF(("DMA still enabled, flushing DCTL.\n"));
    425  1.10.122.1    martin 
    426         1.4  christos 		    sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
    427         1.4  christos 			    | ESPDCTL_DMARD | ESPDCTL_FLUSH;
    428         1.4  christos 		    sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
    429         1.4  christos 			    | ESPDCTL_DMARD;
    430  1.10.122.1    martin 
    431         1.4  christos 		    flushcount++;
    432         1.4  christos 		    state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE
    433         1.4  christos 					   | DMACSR_SUPDATE | DMACSR_ENABLE);
    434         1.4  christos 	    }
    435         1.1       dbj     }
    436         1.4  christos     sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB;
    437         1.4  christos     resid = (sr[NCR_TCM]<<8) + sr[NCR_TCL];
    438         1.1       dbj 
    439         1.4  christos     dma->dd_csr = DMACSR_CLRCOMPLETE | DMACSR_RESET;
    440         1.1       dbj 
    441         1.6       wiz     DPRINTF(("DMA done. remain = %d, state = 0x%x, fifo = 0x%x.\n", resid, state, sr[NCR_FFLAG] & NCRFIFO_FF));
    442         1.1       dbj 
    443         1.4  christos     if (resid != 0)
    444         1.1       dbj     {
    445         1.5   mycroft #if 1
    446         1.6       wiz       printf("WARNING: unexpected %d characters remain in DMA\n",resid);
    447         1.6       wiz 	scsierror("DMA transfer incomplete");
    448         1.1       dbj 	return -1;
    449         1.1       dbj #endif
    450         1.1       dbj     }
    451         1.1       dbj 
    452         1.1       dbj     if (state & DMACSR_BUSEXC)
    453         1.1       dbj     {
    454         1.5   mycroft #if 0
    455         1.6       wiz 	scsierror("DMA failed");
    456         1.1       dbj 	return -1;
    457         1.5   mycroft #endif
    458         1.1       dbj     }
    459         1.4  christos 
    460         1.4  christos     sc->dma_len -= resid;
    461         1.4  christos     if (sc->dma_len < 0)
    462         1.4  christos 	    sc->dma_len = 0;
    463        1.10        he     memcpy(sc->dma_addr, dma_buffer, sc->dma_len);
    464         1.4  christos     sc->sc_state = SCSI_HASBUS;
    465         1.6       wiz     DPRINTF(("DMA done. got %d.\n", sc->dma_len));
    466         1.4  christos     return sc->dma_len;
    467         1.4  christos 
    468         1.6       wiz     /* scsierror("DMA not completed\n"); */
    469  1.10.122.1    martin 
    470         1.4  christos     return 0;
    471         1.1       dbj }
    472