📄 asc.c
字号:
regs->asc_cmd = ASC_CMD_XFER_INFO; readback(regs->asc_cmd); goto done; } /* check for SCSI bus reset */ if (ir & ASC_INT_RESET) { register int i; printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); /* need to flush any pending commands */ for (i = 0; i < ASC_NCMD; i++) { if (!asc->cmd[i]) continue; asc->st[i].error = EIO; asc_end(asc, 0, 0, 0); } /* rearbitrate synchronous offset */ for (i = 0; i < ASC_NCMD; i++) { asc->st[i].sync_offset = 0; asc->st[i].flags = 0; } asc->target = -1; return; } /* check for command errors */ if (ir & ASC_INT_ILL) goto abort; /* check for disconnect */ if (ir & ASC_INT_DISC) { state = &asc->st[asc->target]; switch (ASC_SS(ss)) { case 0: /* device did not respond */ /* check for one of the starting scripts */ switch (asc->script - asc_scripts) { case SCRIPT_TRY_SYNC: case SCRIPT_SIMPLE: case SCRIPT_DATA_IN: case SCRIPT_DATA_OUT: if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { regs->asc_cmd = ASC_CMD_FLUSH; readback(regs->asc_cmd); } state->error = ENXIO; asc_end(asc, status, ss, ir); return; } /* FALLTHROUGH */ default: printf("asc%d: SCSI device %d: unexpected disconnect\n", asc - asc_softc, asc->target); /* * On rare occasions my RZ24 does a disconnect during * data in phase and the following seems to keep it * happy. * XXX Should a scsi disk ever do this?? */ asc->script = &asc_scripts[SCRIPT_RESEL]; asc->state = ASC_STATE_RESEL; state->flags |= DISCONN; regs->asc_cmd = ASC_CMD_ENABLE_SEL; readback(regs->asc_cmd); return; } } /* check for reselect */ if (ir & ASC_INT_RESEL) { unsigned fifo, id, msg; fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; if (fifo < 2) goto abort; /* read unencoded SCSI ID and convert to binary */ msg = regs->asc_fifo & asc->myidmask; for (id = 0; (msg & 1) == 0; id++) msg >>= 1; /* read identify message */ msg = regs->asc_fifo;#ifdef DEBUG if (asc_logp == asc_log) asc_log[NLOG - 1].msg = msg; else asc_logp[-1].msg = msg;#endif asc->state = ASC_STATE_BUSY; asc->target = id; state = &asc->st[id]; asc->script = state->script; state->script = (script_t *)0; if (!(state->flags & DISCONN)) goto abort; state->flags &= ~DISCONN; regs->asc_syn_p = state->sync_period; regs->asc_syn_o = state->sync_offset; regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(regs->asc_cmd); goto done; } /* check if we are being selected as a target */ if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) goto abort; /* * 'ir' must be just ASC_INT_FC. * This is normal if canceling an ASC_ENABLE_SEL. */done: MachEmptyWriteBuffer(); /* watch out for HW race conditions and setup & hold time violations */ ir = regs->asc_status; while (ir != (status = regs->asc_status)) ir = status; if (status & ASC_CSR_INT) goto again; return;abort:#ifdef DEBUG asc_DumpLog("asc_intr");#endif#if 0 panic("asc_intr");#else for (;;);#endif}/* * All the many little things that the interrupt * routine might switch to. *//* ARGSUSED */static intscript_nop(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ return (1);}/* ARGSUSED */static intasc_get_status(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register asc_regmap_t *regs = asc->regs; register int data; /* * Get the last two bytes in the FIFO. */ if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ asc_DumpLog("get_status"); /* XXX */ if (data < 2) { asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; readback(asc->regs->asc_cmd); return (0); } do { data = regs->asc_fifo; } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); } /* save the status byte */ asc->st[asc->target].statusByte = data = regs->asc_fifo;#ifdef DEBUG if (asc_logp == asc_log) asc_log[NLOG - 1].msg = data; else asc_logp[-1].msg = data;#endif /* get the (presumed) command_complete message */ if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) return (1);#ifdef DEBUG printf("asc_get_status: status %x cmd %x\n", asc->st[asc->target].statusByte, data); asc_DumpLog("asc_get_status");#endif return (0);}/* ARGSUSED */static intasc_end(asc, status, ss, ir) register asc_softc_t asc; register int status, ss, ir;{ register ScsiCmd *scsicmd; register State *state; register int i, target; asc->state = ASC_STATE_IDLE; target = asc->target; asc->target = -1; scsicmd = asc->cmd[target]; asc->cmd[target] = (ScsiCmd *)0; state = &asc->st[target];#ifdef DEBUG if (asc_debug > 1) { printf("asc_end: %s target %d cmd %x err %d resid %d\n", scsicmd->sd->sd_driver->d_name, target, scsicmd->cmd[0], state->error, state->buflen); }#endif#ifdef DIAGNOSTIC if (target < 0 || !scsicmd) panic("asc_end");#endif /* look for disconnected devices */ for (i = 0; i < ASC_NCMD; i++) { if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) continue; asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; readback(asc->regs->asc_cmd); asc->state = ASC_STATE_RESEL; asc->script = &asc_scripts[SCRIPT_RESEL]; break; } /* * Look for another device that is ready. * May want to keep last one started and increment for fairness * rather than always starting at zero. */ for (i = 0; i < ASC_NCMD; i++) { /* don't restart a disconnected command */ if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) continue; asc_startcmd(asc, i); break; } /* signal device driver that the command is done */ (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, state->buflen, state->statusByte); return (0);}/* ARGSUSED */static intasc_dma_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 len; /* check for previous chunk in buffer */ if (state->flags & DMA_IN_PROGRESS) { /* * Only count bytes that have been copied to memory. * There may be some bytes in the FIFO if synchonous transfers * are in progress. */ (*asc->dma_end)(asc, state, ASCDMA_READ); ASC_TC_GET(regs, len); len = state->dmalen - len; bcopy(state->dmaBufAddr, state->buf, len); state->buf += len; state->buflen -= len; } /* setup to start reading the next chunk */ len = state->buflen; if (len > state->dmaBufSize) len = state->dmaBufSize; state->dmalen = len; (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); ASC_TC_PUT(regs, len);#ifdef DEBUG if (asc_debug > 2) printf("asc_dma_in: 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_IN]; return (0); } return (1);}/* ARGSUSED */static intasc_last_dma_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 len, fifo; /* copy data from buffer to main memory */ (*asc->dma_end)(asc, state, ASCDMA_READ); ASC_TC_GET(regs, len); fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;#ifdef DEBUG if (asc_debug > 2) printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", state->buflen, state->dmalen, len, fifo);#endif if (fifo) { /* device must be trying to send more than we expect */ regs->asc_cmd = ASC_CMD_FLUSH; readback(regs->asc_cmd); } state->flags &= ~DMA_IN_PROGRESS; len = state->dmalen - len; state->buflen -= len; bcopy(state->dmaBufAddr, state->buf, len); return (1);}/* ARGSUSED */static intasc_resume_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 len; /* setup to start reading the next chunk */ len = state->buflen; if (len > state->dmaBufSize) len = state->dmaBufSize; state->dmalen = len; (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); ASC_TC_PUT(regs, len);#ifdef DEBUG if (asc_debug > 2) printf("asc_resume_in: 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_IN]; return (0); } return (1);}/* ARGSUSED */static intasc_resume_dma_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 len, off; /* setup to finish reading the current chunk */ len = state->dmaresid; off = state->dmalen - len; if ((off & 1) && state->sync_offset) { printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", state->dmalen, len, off); /* XXX */ regs->asc_res_fifo = state->dmaBufAddr[off]; } (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); ASC_TC_PUT(regs, len);#ifdef DEBUG if (asc_debug > 2) printf("asc_resume_dma_in: 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_IN]; return (0); } return (1);}/* ARGSUSED */static intasc_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, fifo; if (state->flags & DMA_IN_PROGRESS) { /* check to be sure previous chunk was finished */ ASC_TC_GET(regs, len); fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; if (len || fifo) printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", state->buflen, state->dmalen, len, fifo); /* XXX */ len += fifo; len = state->dmalen - len; state->buf += len; state->buflen -= len; } /* 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_dma_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_last_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, fifo; ASC_TC_GET(regs, len); fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;#ifdef DEBUG if (asc_debug > 2) printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", state->buflen, state->dmalen, len, fifo);#endif if (fifo) { len += fifo; regs->asc_cmd = ASC_CMD_FLUSH; readback(regs->asc_cmd); printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", state->buflen, state->dmalen, len, fifo); } state->flags &= ~DMA_IN_PROGRESS; len = state->dmalen - len; state->buflen -= len; return (1);}/* ARGSUSED */static intasc_resume_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -