📄 asc.c
字号:
/* setup for this chunk */ len = state->buflen; if (len > state->dmaBufSize) len = state->dmaBufSize; state->dmalen = len; bcopy(state->buf, state->dmaBufAddr, len); (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); ASC_TC_PUT(regs, len);#ifdef DEBUG if (asc_debug > 2) printf("asc_resume_out: buflen %d, len %d\n", state->buflen, len);#endif /* check for next chunk */ state->flags |= DMA_IN_PROGRESS; if (len != state->buflen) { regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; readback(regs->asc_cmd); asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; return (0); } return (1);}/* ARGSUSED */static intasc_resume_dma_out(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register asc_regmap_t *regs = asc->regs; register State *state = &asc->st[asc->target]; register int len, off; /* setup to finish writing this chunk */ len = state->dmaresid; off = state->dmalen - len; if (off & 1) { printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", state->dmalen, len, off); /* XXX */ regs->asc_fifo = state->dmaBufAddr[off]; off++; len--; } (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); ASC_TC_PUT(regs, len);#ifdef DEBUG if (asc_debug > 2) printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", state->dmalen, state->buflen, len, off);#endif /* check for next chunk */ state->flags |= DMA_IN_PROGRESS; if (state->dmalen != state->buflen) { regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; readback(regs->asc_cmd); asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; return (0); } return (1);}/* ARGSUSED */static intasc_sendsync(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register asc_regmap_t *regs = asc->regs; register State *state = &asc->st[asc->target]; /* send the extended synchronous negotiation message */ regs->asc_fifo = SCSI_EXTENDED_MSG; MachEmptyWriteBuffer(); regs->asc_fifo = 3; MachEmptyWriteBuffer(); regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; MachEmptyWriteBuffer(); regs->asc_fifo = SCSI_MIN_PERIOD; MachEmptyWriteBuffer(); regs->asc_fifo = ASC_MAX_OFFSET; /* state to resume after we see the sync reply message */ state->script = asc->script + 2; state->msglen = 0; return (1);}/* ARGSUSED */static intasc_replysync(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register asc_regmap_t *regs = asc->regs; register State *state = &asc->st[asc->target];#ifdef DEBUG if (asc_debug > 2) printf("asc_replysync: %x %x\n", asc_to_scsi_period[state->sync_period] * asc->tb_ticks, state->sync_offset);#endif /* send synchronous transfer in response to a request */ regs->asc_fifo = SCSI_EXTENDED_MSG; MachEmptyWriteBuffer(); regs->asc_fifo = 3; MachEmptyWriteBuffer(); regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; MachEmptyWriteBuffer(); regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; MachEmptyWriteBuffer(); regs->asc_fifo = state->sync_offset; regs->asc_cmd = ASC_CMD_XFER_INFO; readback(regs->asc_cmd); /* return to the appropriate script */ if (!state->script) {#ifdef DEBUG asc_DumpLog("asc_replsync");#endif panic("asc_replysync"); } asc->script = state->script; state->script = (script_t *)0; return (0);}/* ARGSUSED */static intasc_msg_in(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register asc_regmap_t *regs = asc->regs; register State *state = &asc->st[asc->target]; register int msg; int i; /* read one message byte */ msg = regs->asc_fifo;#ifdef DEBUG if (asc_logp == asc_log) asc_log[NLOG - 1].msg = msg; else asc_logp[-1].msg = msg;#endif /* check for multi-byte message */ if (state->msglen != 0) { /* first byte is the message length */ if (state->msglen < 0) { state->msglen = msg; return (1); } if (state->msgcnt >= state->msglen) goto abort; state->msg_in[state->msgcnt++] = msg; /* did we just read the last byte of the message? */ if (state->msgcnt != state->msglen) return (1); /* process an extended message */#ifdef DEBUG if (asc_debug > 2) printf("asc_msg_in: msg %x %x %x\n", state->msg_in[0], state->msg_in[1], state->msg_in[2]);#endif switch (state->msg_in[0]) { case SCSI_SYNCHRONOUS_XFER: state->flags |= DID_SYNC; state->sync_offset = state->msg_in[2]; /* convert SCSI period to ASC period */ i = state->msg_in[1] / asc->tb_ticks; if (i < asc->min_period) i = asc->min_period; else if (i >= asc->max_period) { /* can't do sync transfer, period too long */ printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", asc - asc_softc, asc->target, i); i = asc->max_period; state->sync_offset = 0; } if ((i * asc->tb_ticks) != state->msg_in[1]) i++; state->sync_period = i & 0x1F; /* * If this is a request, check minimums and * send back an acknowledge. */ if (!(state->flags & TRY_SYNC)) { regs->asc_cmd = ASC_CMD_SET_ATN; readback(regs->asc_cmd); if (state->sync_period < asc->min_period) state->sync_period = asc->min_period; if (state->sync_offset > ASC_MAX_OFFSET) state->sync_offset = ASC_MAX_OFFSET; asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; regs->asc_syn_p = state->sync_period; readback(regs->asc_syn_p); regs->asc_syn_o = state->sync_offset; readback(regs->asc_syn_o); regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(regs->asc_cmd); return (0); } regs->asc_syn_p = state->sync_period; readback(regs->asc_syn_p); regs->asc_syn_o = state->sync_offset; readback(regs->asc_syn_o); goto done; default: printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", asc - asc_softc, asc->target, state->msg_in[0]); goto reject; } } /* process first byte of a message */#ifdef DEBUG if (asc_debug > 2) printf("asc_msg_in: msg %x\n", msg);#endif switch (msg) {#if 0 case SCSI_MESSAGE_REJECT: printf(" did not like SYNCH xfer "); /* XXX */ state->flags |= DID_SYNC; regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(regs->asc_cmd); status = asc_wait(regs, ASC_CSR_INT); ir = regs->asc_intr; /* some just break out here, some dont */ if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { regs->asc_fifo = SCSI_ABORT; regs->asc_cmd = ASC_CMD_XFER_INFO; readback(regs->asc_cmd); status = asc_wait(regs, ASC_CSR_INT); ir = regs->asc_intr; } if (ir & ASC_INT_DISC) { asc_end(asc, status, 0, ir); return (0); } goto status;#endif case SCSI_EXTENDED_MSG: /* read an extended message */ /* setup to read message length next */ state->msglen = -1; state->msgcnt = 0; return (1); case SCSI_NO_OP: break; case SCSI_SAVE_DATA_POINTER: /* expect another message */ return (1); case SCSI_RESTORE_POINTERS: /* * Need to do the following if resuming synchonous data in * on an odd byte boundary. regs->asc_cnfg2 |= ASC_CNFG2_RFB; */ break; case SCSI_DISCONNECT: if (state->flags & DISCONN) goto abort; state->flags |= DISCONN; regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(regs->asc_cmd); asc->script = &asc_scripts[SCRIPT_DISCONNECT]; return (0); default: printf("asc%d: SCSI device %d: rejecting message 0x%x\n", asc - asc_softc, asc->target, msg); reject: /* request a message out before acknowledging this message */ state->msg_out = SCSI_MESSAGE_REJECT; regs->asc_cmd = ASC_CMD_SET_ATN; readback(regs->asc_cmd); }done: /* return to original script */ regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(regs->asc_cmd); if (!state->script) { abort:#ifdef DEBUG asc_DumpLog("asc_msg_in");#endif panic("asc_msg_in"); } asc->script = state->script; state->script = (script_t *)0; return (0);}/* ARGSUSED */static intasc_disconnect(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register State *state = &asc->st[asc->target];#ifdef DIAGNOSTIC if (!(state->flags & DISCONN)) { printf("asc_disconnect: device %d: DISCONN not set!\n", asc->target); }#endif asc->target = -1; asc->state = ASC_STATE_RESEL; return (1);}/* * DMA handling routines. For a turbochannel device, just set the dmar. * For the I/O ASIC, handle the actual DMA interface. */static voidtb_dma_start(asc, state, cp, flag) asc_softc_t asc; State *state; caddr_t cp; int flag;{ if (flag == ASCDMA_WRITE) *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); else *asc->dmar = ASC_DMA_ADDR(cp);}static voidtb_dma_end(asc, state, flag) asc_softc_t asc; State *state; int flag;{}static voidasic_dma_start(asc, state, cp, flag) asc_softc_t asc; State *state; caddr_t cp; int flag;{ register volatile u_int *ssr = (volatile u_int *) ASIC_REG_CSR(asic_base); u_int phys, nphys; /* stop DMA engine first */ *ssr &= ~ASIC_CSR_DMAEN_SCSI; *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; phys = MACH_CACHED_TO_PHYS(cp); cp = (caddr_t)pmax_trunc_page(cp + NBPG); nphys = MACH_CACHED_TO_PHYS(cp); asc->dma_next = cp; asc->dma_xfer = state->dmalen - (nphys - phys); *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = ASIC_DMA_ADDR(phys); *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = ASIC_DMA_ADDR(nphys); if (flag == ASCDMA_READ) *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; else *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; MachEmptyWriteBuffer();}static voidasic_dma_end(asc, state, flag) asc_softc_t asc; State *state; int flag;{ register volatile u_int *ssr = (volatile u_int *) ASIC_REG_CSR(asic_base); register volatile u_int *dmap = (volatile u_int *) ASIC_REG_SCSI_DMAPTR(asic_base); register u_short *to; register int w; int nb; *ssr &= ~ASIC_CSR_DMAEN_SCSI; to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); *dmap = -1; *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; MachEmptyWriteBuffer(); if (flag == ASCDMA_READ) { MachFlushDCache(MACH_PHYS_TO_CACHED( MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { /* pick up last upto6 bytes, sigh. */ /* Last byte really xferred is.. */ w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); *to++ = w; if (--nb > 0) { w >>= 16; *to++ = w; } if (--nb > 0) { w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); *to++ = w; } } }}#ifdef notdef/* * Called by asic_intr() for scsi dma pointer update interrupts. */voidasc_dma_intr(){ asc_softc_t asc = &asc_softc[0]; u_int next_phys; asc->dma_xfer -= NBPG; if (asc->dma_xfer <= -NBPG) { volatile u_int *ssr = (volatile u_int *) ASIC_REG_CSR(asic_base); *ssr &= ~ASIC_CSR_DMAEN_SCSI; } else { asc->dma_next += NBPG; next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); } *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = ASIC_DMA_ADDR(next_phys); MachEmptyWriteBuffer();}#endif#ifdef DEBUGasc_DumpLog(str) char *str;{ register struct asc_log *lp; register u_int status; printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, asc_debug_bn, asc_debug_sz); lp = asc_logp; do { status = lp->status; printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", status >> 24, lp->target, (status >> 16) & 0xFF, (status >> 8) & 0xFF, status & 0XFF, lp->state, asc_scripts[lp->state].condition, lp->msg, lp->resid); if (++lp >= &asc_log[NLOG]) lp = asc_log; } while (lp != asc_logp);}#endif#endif /* NASC > 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -