📄 ncr.c
字号:
if (ncr_flushbyte(ncr, offset, (u_char) (bpr>>24))) return (FAILURE); break; default: break; } ncr->n_lastbcr += (addr & 0x3); return (SUCCESS);}static intncr_cobra_dma_cleanup(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register u_long amt, reqamt; register u_char junk; DISABLE_DMA(ncr); amt = GET_DMA_ADDR(ncr); reqamt = ncr->n_lastcount; /* * Now try and figure out how much actually transferred */ ncr->n_lastbcr = reqamt - ((amt & 0xfffff) - (unsigned int) sp->cmd_data & 0xfffff); PRINTF3("ncr_dma_cleanup: count= %x, data= %x, amt= %x, bcr= %x\n", reqamt, sp->cmd_data, amt, ncr->n_lastbcr); if ((ncr->n_lastbcr != reqamt) && (!(N_SBC->tcr & NCR_TCR_LAST)) && (sp->cmd_flags & CFLAG_DMASEND)) { ncr->n_lastbcr++; } /* * Now check for dma related errors */ if (ncr_cobra_dma_chkerr(ncr, ncr->n_lastbcr)) { sp->cmd_pkt.pkt_reason = CMD_DMA_DERR; return (FAILURE); } /* * okay, now figure out an adjustment for bytes * left over in the or a byte pack register. */ if ((sp->cmd_flags & CFLAG_DMASEND) == 0) { if (ncr_cobra_dma_recv(ncr)) return (FAILURE); } if (ncr->n_lastbcr < 0) { EPRINTF("ncr_dma_cleanup: dma overrun by %d bytes\n", -ncr->n_lastbcr); ncr->n_lastbcr = 0; } /* * Shut off dma engine */ SET_DMA_ADDR(ncr, 0); SET_DMA_COUNT(ncr, 0); /* * And return result of common cleanup routine */ return (ncr_dma_cleanup(ncr));}#endif sun4#ifdef sun3static voidncr_ob_dma_setup(ncr)struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register int reqamt; u_int dmaaddr; if (sp->cmd_flags & CFLAG_NEEDSEG) { panic("ncr_ob_dma_setup: need seg\n"); /*NOTREACHED*/ } if ((sp->cmd_flags & CFLAG_DMAVALID) == 0) { panic("ncr_ob_dma_setup: need seg\n"); /*NOTREACHED*/ } if ((u_long) sp->cmd_data & 0x1) { panic("dma not on word boundary"); /*NOTREACHED*/ } ncr->n_lastcount = reqamt = scsi_chkdma(sp, NCR_MAX_DMACOUNT); if (reqamt == 0) return; PRINTF3("ncr_ob_dma_setup: addr= %x, reqamt= %x\n", sp->cmd_data, reqamt); /* reset fifo */ SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES)); SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES)); if (sp->cmd_flags & CFLAG_DMASEND) { SET_CSR(ncr, (GET_CSR(ncr)) | NCR_CSR_SEND); } else { SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND); } /* Set bcr */ SET_BCR(ncr, reqamt); /* reset udc */ N_DMA->udc_raddr = UDC_ADR_COMMAND; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = UDC_CMD_RESET; DELAY(NCR_UDC_WAIT); /* set up udc dma information */ ncr->n_lastdma = dmaaddr = sp->cmd_data; if (dmaaddr < Dmabase) dmaaddr |= Dmabase; ncr->n_udc->haddr = ((dmaaddr & 0xff0000) >> 8) | UDC_ADDR_INFO; ncr->n_udc->laddr = dmaaddr & 0xffff; ncr->n_udc->hcmr = UDC_CMR_HIGH; ncr->n_udc->count = reqamt / 2; /* #bytes -> #words */ if (sp->cmd_flags & CFLAG_DMASEND) { ncr->n_udc->rsel = UDC_RSEL_SEND; ncr->n_udc->lcmr = UDC_CMR_LSEND; if (reqamt & 1) ncr->n_udc->count++; } else { ncr->n_udc->rsel = UDC_RSEL_RECV; ncr->n_udc->lcmr = UDC_CMR_LRECV; } /* initialize udc chain address register */ N_DMA->udc_raddr = UDC_ADR_CAR_HIGH; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = (((int)ncr->n_udc) & 0xff0000) >> 8; DELAY(NCR_UDC_WAIT); N_DMA->udc_raddr = UDC_ADR_CAR_LOW; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = ((int)ncr->n_udc) & 0xffff; DELAY(NCR_UDC_WAIT); /* initialize udc master mode register */ N_DMA->udc_raddr = UDC_ADR_MODE; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = UDC_MODE; DELAY(NCR_UDC_WAIT); /* issue channel interrupt enable command, in case of error, to udc */ N_DMA->udc_raddr = UDC_ADR_COMMAND; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = UDC_CMD_CIE; DELAY(NCR_UDC_WAIT);}/* * Cleanup up the SCSI control logic after a dma transfer. */static intncr_ob_dma_cleanup(ncr)struct ncr *ncr;{ struct scsi_cmd *sp = CURRENT_CMD(ncr); u_char junk; int amt, csr; /* * okay, now figure out an adjustment for bytes left over in a fifo * or a byte pack register.... */ if ((sp->cmd_flags & CFLAG_DMASEND) == 0) { if (ncr_ob_dma_recv(ncr)) return (FAILURE); } /* * disable dma controller */ N_DMA->udc_raddr = UDC_ADR_COMMAND; DELAY(NCR_UDC_WAIT); N_DMA->udc_rdata = UDC_CMD_RESET; DELAY(NCR_UDC_WAIT); N_DMA->bcr = 0; SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND); /* * reset fifo */ SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES)); SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES)); /* * And return result of common cleanup routine */ return (ncr_dma_cleanup(ncr));}/* * Handle special dma receive situations, e.g. an odd number of bytes in * a dma transfer. */static intncr_ob_dma_recv(ncr)register struct ncr *ncr;{ register int bcr, offset; u_char byte; /* * handle the onboard scsi situations */ offset = ncr->n_lastdma + (ncr->n_lastcount - ncr->n_lastbcr); bcr = N_DMA->bcr; N_DMA->udc_raddr = UDC_ADR_COUNT; DELAY(NCR_UDC_WAIT); /* * wait for the fifo to empty */ if (ncr_csrwait(ncr, NCR_CSR_FIFO_EMPTY, NCR_WAIT_COUNT*3, 1)) { printf("%s%d: fifo never drained\n", CNAME, CNUM); return (FAILURE); } /* * Didn't transfer any data. "Just say no" and leave, * rather than erroneously executing left over byte code. * The bcr + 1 above wards against 5380 prefetch. */ if (bcr == ncr->n_lastcount) { return (SUCCESS); } else if ((bcr + 1) == ncr->n_lastcount) { ncr->n_lastbcr = ncr->n_lastcount; } /* * For either of the following cases, it appears that the * n_lastbcr count latched up in ncrsvc is, in fact, correct. * Therefore, we don't need to adjust it here. */ /* handle odd byte */ if ((ncr->n_lastcount - bcr) & 1) { byte = ((N_DMA->fifo_data & 0xff00) >> 8); if (ncr_flushbyte(ncr, offset - 1, byte)) { return (FAILURE); } PRINTF1("%s%d: odd byte recv: lastcount %d bcr %d\n", CNAME, CNUM, ncr->n_lastcount, ncr->n_lastbcr); } else if ((N_DMA->udc_rdata * 2) - bcr == 2) { /* * The udc may not dma the last word from the fifo_data * register into memory due to how the hardware turns * off the udc at the end of the dma operation. */ byte = ((N_DMA->fifo_data & 0xff00) >> 8); if (ncr_flushbyte(ncr, offset - 2, byte)) { return (FAILURE); } byte = (N_DMA->fifo_data & 0xff); if (ncr_flushbyte(ncr, offset - 1, byte)) { return (FAILURE); } PRINTF1("%s%d: last word: lastcount %d bcr %d\n", CNAME, CNUM, ncr->n_lastcount, ncr->n_lastbcr); } return (SUCCESS);}#endif sun3static intncr_vme_dma_recv(ncr)register struct ncr *ncr;{ register amt, csr; register u_short bprmsw, bprlsw; u_long offset; /* * Grabs last few bytes which may not have been dma'd. Worst * case is when longword dma transfers are being done and there * are 3 bytes leftover. If BPCON bit is set then longword dma * was being done, otherwise word dma was being done. */ csr = GET_CSR(ncr); if ((amt = NCR_CSR_LOB_CNT(csr)) == 0) { return (SUCCESS); } offset = ncr->n_lastdma + (ncr->n_lastcount - ncr->n_lastbcr); PRINTF3("%s%d: receive flushing %d bytes to offset %d in xfer of %d\n", CNAME, CNUM, amt, offset, ncr->n_lastcount); /* * It *may* be that the order that * the byte pack register is read * is significant. * */ bprmsw = N_CTL->bpr.msw; bprlsw = N_CTL->bpr.lsw; if (csr & NCR_CSR_BPCON) { return (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprlsw))); } switch (amt) { case 3: if (ncr_flushbyte(ncr, offset-3, (u_char) hibyte(bprmsw))) return (FAILURE); if (ncr_flushbyte(ncr, offset-2, (u_char) lobyte(bprmsw))) return (FAILURE); if (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprlsw))) return (FAILURE); break; case 2: if (ncr_flushbyte(ncr, offset-2, (u_char) hibyte(bprmsw))) return (FAILURE); if (ncr_flushbyte(ncr, offset-1, (u_char) lobyte(bprmsw))) return (FAILURE); break; case 1: if (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprmsw))) return (FAILURE); break; } return (SUCCESS);}static intncr_vme_dma_cleanup(ncr)register struct ncr *ncr;{ struct scsi_cmd *sp = CURRENT_CMD(ncr); register u_int bcr, reqamt; DISABLE_DMA(ncr); /* * Now try and figure out how much actually transferred */ bcr = GET_BCR(ncr); reqamt = ncr->n_lastcount; /* * bcr does not reflect how many bytes were actually * transferred for VME. * * SCSI-3 VME interface is a little funny on writes: * if we have a disconnect, the dma has overshot by * one byte and needs to be incremented. This is * true if we have not transferred either all data * or no data. */ if ((sp->cmd_flags & CFLAG_DMASEND) && bcr != reqamt && bcr) { if (ncr->n_lastbcr != 0) bcr = ncr->n_lastbcr + 1; else bcr++; } else if ((sp->cmd_flags & CFLAG_DMASEND) == 0) { bcr = ncr->n_lastbcr; if (ncr_vme_dma_recv(ncr)) { return (FAILURE); } } /* * rewrite last bcr count- it might have been changed by circumstances. */ ncr->n_lastbcr = bcr; /* * Shut off dma engine */ SET_DMA_ADDR(ncr, 0); SET_DMA_COUNT(ncr, 0); SET_BCR(ncr, 0); SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND); /* * reset fifo */ SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES)); SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES)); /* * And return result of common cleanup routine */ return (ncr_dma_cleanup(ncr));}static intncr_3e_dma_cleanup(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); /* * Now try and figure out how much actually transferred */ ncr->n_lastbcr = (u_long) (u_short) GET_DMA_COUNT(ncr); if (sp->cmd_flags & CFLAG_DMASEND) { /* * check for a pre-fetch botch * XXX: I'm not sure I believe this. It was lifted from se.c. */ if (ncr->n_lastbcr == 0xffff) ncr->n_lastbcr = 0; else ncr->n_lastbcr++; } /* * Shut off dma engine */ SET_DMA_ADDR(ncr, 0); SET_DMA_COUNT(ncr, 0); /* * Copy out data from onboard dma buffer (if receive case) */ if ((sp->cmd_flags & CFLAG_DMASEND) == 0) { if (ncr_3e_storedata(ncr)) { return (FAILURE); } } /* * And return result of common cleanup routine */ return (ncr_dma_cleanup(ncr));}/* * Cleanup operations, where the dma engine doesn't do it all. * * XXXXXXXXXXXXXXXXXXXXXXXXXXX: FIX ME :XXXXXXXXXXXXXXXXXXXXXXXXXXXX * XXXXXXXXX XXXXXXXXXXXX * XXXXXXXXX All These Routines Need to XXXXXXXXXXXX * XXXXXXXXX be rewritten to *not* refer XXXXXXXXXXXX * XXXXXXXXX to DVMA. This must happen! XXXXXXXXXXXX * XXXXXXXXX XXXXXXXXXXXX * XXXXXXXXXXXXXXXXXXXXXXXXXXX: FIX ME :XXXXXXXXXXXXXXXXXXXXXXXXXXXX * */static intncr_flushbyte (ncr, offset, byte)struct ncr *ncr;int offset;u_char byte;{ u_char *mapaddr; u_int pv; if (MBI_MR(offset) < dvmasize) { DVMA[offset] = byte; return (SUCCESS); }#ifdef sun3x pv = btop (VME24D16_BASE + (offset & VME24D16_MASK));#else sun3x pv = PGT_VME_D16 | VME24_BASE | btop(offset & VME24_MASK);#endif sun3x mapaddr = (u_char *) ((u_long) kmxtob(ncr->n_kment) | (u_long) MBI_OFFSET(offset)); segkmem_mapin(&kseg, (addr_t) (((int)mapaddr) & PAGEMASK), (u_int) mmu_ptob(1), PROT_READ | PROT_WRITE, pv, 0); *mapaddr = byte; segkmem_mapout(&kseg, (addr_t) (((int)mapaddr) & PAGEMASK), (u_int) mmu_ptob(1)); return (SUCCESS);}static intncr_3e_fetchdata(ncr)struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); if (MBI_MR(sp->cmd_data) < dvmasize) { bcopy(sp->cmd_data + (u_long) DVMA, ncr->n_dmabuf, ncr->n_lastcount); } else { panic("3/E dma from VME board"); /*NOTREACHED*/ } return (SUCCESS);}static intncr_3e_storedata(ncr)struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); if (MBI_MR(sp->cmd_data) < dvmasize) { bcopy(ncr->n_dmabuf, sp->cmd_data + (u_long) DVMA, ncr->n_lastcount); } else { panic("3/E dma to VME board"); /*NOTREACHED*/ } return (SUCCESS);}/* * Common routine to enable the SBC for a dma operation. */static voidncr_dma_enable(ncr, direction)register struct ncr *ncr;int direction;{ register s; u_char junk; s = splhigh(); /* (possibly) time critical */ if (ncr->n_type == IS_3_50) { /* * issue start chain command to udc */ N_DMA->udc_rdata = UDC_CMD_STRT_CHN; } else if (ncr->n_type == IS_SCSI3) { /* * Stuff count registers */ SET_DMA_COUNT(ncr, ncr->n_lastcount); SET_BCR(ncr, ncr->n_lastcount); } if (direction) { /* 1 = recv */ N_SBC->tcr = TCR_DATA_IN; junk = N_SBC->clr; N_SB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -