📄 sm.c
字号:
case SC_WRITE_VERIFY: smsnap->sync_chk = SM_SEND_DATA; break; default: smsnap->sync_chk = SM_NO_DATA; } /* clear some status */ smsnap->cur_err = (smsnap->scsi_status = ZERO); smsnap->cur_retry = ZERO; smsnap->cur_state = STATE_SEL_REQ; ESP_WR.timeout = DEF_TIMEOUT; ESP_WR.busid = h_sip->unit; /* target SCSI ID */ DPRINTF1("smdoit: selecting target= %x\n", h_sip->unit); DEBUG_DELAY(1000000); toutcnt = LOOP_CMDTOUT; ESP_WR.cmd = CMD_SEL_NOATN; /* NO identify message */ while ((--toutcnt) && (smsnap->cur_err == ZERO) && (smsnap->cur_state != STATE_FREE)) { /* poll on ESP_INT thru DVMA status reg */ if (dvma->ctl_stat & DVMA_INTPEND) { sm_intr(h_sip); toutcnt = LOOP_CMDTOUT; } } DPRINTF2("smdoit: err= %x, state= %x\n", smsnap->cur_err, smsnap->cur_state); DPRINTF2("smdoit: resid= %x, status= %x\n", h_sip->cc, smsnap->esp_stat); cp = (u_char *)scb; *cp = smsnap->scsi_status; /* return scsi bus status */ DPRINTF1("smdoit: done, bus_status= %x\n", smsnap->scsi_status); DEBUG_DELAY(1000000); if ((toutcnt == ZERO) || (smsnap->cur_err)) { EPRINTF2("sm_cmd: CMD_TIMED-OUT, err= %x, toutcnt= %x\n", smsnap->cur_err, toutcnt); EPRINTF2("sm_cmd: cmd= %x, esp_stat= %x\n", cdb->scc_cmd, ESP_RD.stat); EPRINTF2("sm_cmd: state= %x, cc= %x\n", smsnap->cur_state, h_sip->cc); EPRINTF2("sm_cmd: dma_stat= %x, dma_addr= %x\n", dvma->ctl_stat, dvma->dma_addr); DEBUG_DELAY(1000000); return(FAIL); } return (h_sip->cc); /* successful */}static intsm_dma_setup(h_sip) register struct host_saioreq *h_sip;{ register struct scsi_sm_reg *smr; register struct udc_table *dvma; register struct sm_snap *smsnap = &smreg_info;#ifdef SMDEBUG u_char *ptr; int i;#endif SMDEBUG if ((h_sip->cc == ZERO) || (smsnap->sync_chk == SM_NO_DATA)) { DPRINTF1("sm_dma_setup: return due to xfr_cnt= %x\n", h_sip->cc); return; } /* get to scsi control logic registers */ smr = (struct scsi_sm_reg *)h_sip->devaddr; dvma = (struct udc_table *)h_sip->dmaaddr; #ifdef SMDEBUG DPRINTF1("sm_dma_setup: ORG_addr= %x, data= ", h_sip->ma); ptr = (u_char *)h_sip->ma; for (i = 0; i < 20; i++, ptr++) { DPRINTF1(" %x ", *ptr); } DPRINTF1("\nsm_dma_setup: ORG_cnt= %x\n", h_sip->cc);#endif SMDEBUG dvma->dma_addr = (u_long)h_sip->ma; /* set dma address */ ESP_WR.xcnt_lo = (u_char)h_sip->cc; ESP_WR.xcnt_hi = (u_char)(h_sip->cc >> 8); ESP_WR.cmd = CMD_NOP | CMD_DMA; /* NOP needed */ DPRINTF2("sm_dma_setup: xcnt_lo= %x, xcnt_hi= %x\n", ESP_RD.xcnt_lo, ESP_RD.xcnt_hi); /* enable DMA */ if (smsnap->sync_chk == SM_SEND_DATA) { DPRINTF("sm_cmd: setting a write to SCSI\n"); dvma->ctl_stat |= DVMA_ENDVMA; dvma->ctl_stat &= ~DVMA_WRITE; } else { DPRINTF("sm_cmd: setting a read to SCSI\n"); dvma->ctl_stat |= DVMA_ENDVMA | DVMA_WRITE; } DEBUG_DELAY(1000000);}/* * Reset some register information after a dma operation. */static intsm_dma_cleanup(h_sip, espstat) register struct host_saioreq *h_sip; u_char espstat;{ register struct scsi_sm_reg *smr; register struct udc_table *dvma; register struct sm_snap *smsnap = &smreg_info; register int i; u_long toutcnt; u_short dma_cnt, esp_cnt, xfrcnt, fifo_cnt, req_cnt;#ifdef SMDEBUG u_char *ptr; DPRINTF1("sm_dma_cleanup: ORG_addr= %x, NEW_data= ", h_sip->ma); ptr = (u_char *)h_sip->ma; for (i = 0; i < 20; i++, ptr++) { DPRINTF1(" %x ", *ptr); } DPRINTF1("\nsm_dma_cleanup: ORG_cnt= %x\n", h_sip->cc);#endif SMDEBUG req_cnt = h_sip->cc; if ((req_cnt == ZERO) || (smsnap->sync_chk == SM_NO_DATA)) { DPRINTF2("sm_dma_setup: return, xfr_cnt= %x, stat= %x\n", req_cnt, espstat); return(ZERO); } /* get to scsi control logic registers */ smr = (struct scsi_sm_reg *)h_sip->devaddr; /* get to scsi control logic registers */ smr = (struct scsi_sm_reg *)h_sip->devaddr; dvma = (struct udc_table *)h_sip->dmaaddr; dvma->ctl_stat &= ~DVMA_ENDVMA; toutcnt = dvma->ctl_stat; DPRINTF2("sm_dma_cleanup: dvma_stat= %x, addr= %x\n", toutcnt, dvma->dma_addr); DEBUG_DELAY(1000000); if (toutcnt & DVMA_REQPEND) { toutcnt = LOOP_4SEC; /* must be over 2sec */ while ((dvma->ctl_stat & DVMA_REQPEND) && (--toutcnt)) ; if (toutcnt == ZERO) { EPRINTF1("sm_dma_cleanup: DVMA-scsi REQ_PEND struck, stat= %x\n", dvma->ctl_stat); smsnap->cur_err = SE_REQPEND; return(1); } } if (smsnap->sync_chk == SM_RECV_DATA) { DPRINTF("sm_dma_cleanup: send DVMA_drain\n"); DEBUG_DELAY(1000000); dvma->ctl_stat |= DVMA_DRAIN; /* send DRAIN anyway */ i = LOOP_2MSEC; while ((dvma->ctl_stat & DVMA_DRAIN) && (--i)); if (i == ZERO) { EPRINTF1("sm_dma_cleanup: DVMA-scsi drain stuck, stat= %x\n", dvma->ctl_stat); smsnap->cur_err = SE_DVMAERR; dvma->ctl_stat |= DVMA_FLUSH; dvma->ctl_stat &= ~(DVMA_ENDVMA | DVMA_WRITE); return(1); } } DEBUG_DELAY(1000000); dvma->ctl_stat |= DVMA_FLUSH; /* self-clear */ /* disable DVMA_xfr */ dvma->ctl_stat &= ~(DVMA_ENDVMA | DVMA_WRITE); /* see how much DVMA xfr'd */ DPRINTF2("sm_dma_cleanup: ORIG addr= %x, cnt= %x\n", h_sip->ma, req_cnt); toutcnt = dvma->dma_addr; DPRINTF2("sm_dma_cleanup: espstat= %x, DVMA_addr= %x\n", espstat, toutcnt); dma_cnt = (u_short)toutcnt - (u_short)h_sip->ma; /* see how much ESP xfr'd */ fifo_cnt = ESP_RD.fifo_flag & KEEP_5BITS; DPRINTF2("sm_dma_cleanup: fifo_cnt= %x, dma_cnt= %x\n", fifo_cnt, dma_cnt); /* Figure out how much the esp chip may have xferred * If the XZERO bit is set, we can assume that the * ESP xferred all we asked for. */ if (espstat & ESP_STAT_XZERO) esp_cnt = req_cnt - fifo_cnt; else { xfrcnt = ESP_RD.xcnt_hi << 8; xfrcnt |= ((u_short)ESP_RD.xcnt_lo & KEEP_LBYTE); esp_cnt = req_cnt - xfrcnt; DPRINTF1("sm_dma_cleanup: ESP_cntr= %x\n", xfrcnt); /* correct ESP xfr_cnt reported error */ if ((esp_cnt == 0) && (dma_cnt > 16)) { esp_cnt = dma_cnt & (0xf); } esp_cnt -= fifo_cnt; } /* If we were sending out the scsi bus, then we believe the * (possibly faked) transfer count register, since the esp * chip may have prefetched to fill it's fifo. */ DPRINTF2("sm_dma_cleanup: dir= %x, espcnt= %x\n", smsnap->sync_chk, esp_cnt); if (smsnap->sync_chk == SM_SEND_DATA) xfrcnt = esp_cnt; else { /* Else, if we were coming from the scsi bus, we only count * that which got pumped through the dma engine. */ xfrcnt = dma_cnt; } DPRINTF2("sm_dma_cleanup: dir= %x, xfrcnt= %x\n", smsnap->sync_chk, xfrcnt); /* updated dma_count. NOTE: different from OS-> update the count */ /* to remaining bytes; while HERE = return to upper level with */ /* exact amount of bytes transferred */ h_sip->cc = xfrcnt; #ifdef notdef /* skip updating the addr, upper level driver might reuse the address */ /* without restoring to the original value (expecting NO change) */ h_sip->ma += xfrcnt; #endif notdef DPRINTF2("sm_dma_cleanup: FINAL addr= %x, cnt= %x\n", h_sip->ma, h_sip->cc); smsnap->sync_chk = SM_NO_DATA; if (fifo_cnt) ESP_WR.cmd = CMD_FLUSH; return(ZERO);}/* * Reset SCSI control logic. */static intsm_reset(h_sip, cond) register struct host_saioreq *h_sip; int cond;{ register struct scsi_sm_reg *smr; register struct udc_table *dvma; register struct sm_snap *smsnap = &smreg_info; register int i; u_long toutcnt; /* get to scsi control logic registers */ smr = (struct scsi_sm_reg *)h_sip->devaddr; dvma = (struct udc_table *)h_sip->dmaaddr; DPRINTF2("sm_reset: state= %x, dma_stat= %x\n", smsnap->cur_state, dvma->ctl_stat); DEBUG_DELAY(1000000); if (dvma->ctl_stat & DVMA_REQPEND) smsnap->cur_state = STATE_DVMA_STUCK; ESP_WR.conf = ESP_CONF_DISRINT; /* disable reset INT */ /* for hard reset, cur_state must be STATE_RESET */ switch (cond) { case RESET_EXT_ONLY: DPRINTF("sm_reset: reset ESP/SCSI bus only\n"); ESP_WR.cmd = CMD_RESET_ESP; /* hard-reset ESP chip */ ESP_WR.cmd = CMD_NOP; /* needed for ESP bug */ ESP_WR.cmd = CMD_RESET_SCSI; ESP_WR.cmd = CMD_NOP; /* NOP needed for ESP bug */ for (toutcnt = ZERO; toutcnt < LOOP_4SEC; toutcnt++); i = ESP_RD.intr; /* read to clear reset interrupt */#ifdef linti = i;#endif lint break; case RESET_INT_ONLY: DPRINTF("sm_reset: reset ESP only\n"); /* DVMA_EN = ZERO, INTEN=ZERO, FLUSH=1 */ dvma->ctl_stat = DVMA_FLUSH; /* soft dvma clear */ DELAY(100); dvma->ctl_stat = ZERO; /* clear it */ /* NO ints */ ESP_WR.cmd = CMD_RESET_ESP; /* hard-reset ESP chip */ ESP_WR.cmd = CMD_NOP; /* needed for ESP bug */ break; case RESET_ALL_SCSI: default: DPRINTF("sm_reset: reset DVMA/ESP/SCSI bus\n"); /* implied a reset to both ESP and SCSI bus */ dvma->ctl_stat = DVMA_RESET; /* hard DVMA reset */ DPRINTF1("sm_reset: dvma_stat= %x\n", dvma->ctl_stat); DELAY(100); dvma->ctl_stat = ZERO; /* clear reset */ ESP_WR.cmd = CMD_RESET_SCSI; ESP_WR.cmd = CMD_NOP; /* NOP needed for ESP bug */ /* allow more than 2 second for scsi reset to settle */ /* Give reset scsi devices time to recover (> 2 Sec) */ for (toutcnt = ZERO; toutcnt < LOOP_4SEC; toutcnt++); i = ESP_RD.intr; /* read to clear reset interrupt */#ifdef linti = i;#endif lint } /* enable parity, enable reset_int, and set host bus_id */ ESP_WR.clock_conv = DEF_CLK_CONV; ESP_WR.timeout = DEF_TIMEOUT; ESP_WR.sync_offset = ZERO; /* async */#ifdef notdef /* ignore parity enable for backward campatibilty with old shoebox */ ESP_WR.conf = ESP_CONF_PAREN | DEF_ESP_HOSTID;#endif ESP_WR.conf = DEF_ESP_HOSTID; DPRINTF1("sm_reset: esp_conf= %x\n", ESP_RD.conf); DEBUG_DELAY(1000000); /* set up some default sm_snap */ /* "cur_err, cur_retry, and scsi_status" */ /* will be cleared in "sm_cmd() */ smsnap->cur_state = STATE_FREE; smsnap->scsi_message = SC_COMMAND_COMPLETE; /* dvam's ctl_stat is ZERO, which means no INTEN; */ DPRINTF1("sm_reset: done, DVMA_stat= %x\n", dvma->ctl_stat);}/* * Handle a scsi interrupt. */sm_intr(h_sip) struct host_saioreq *h_sip;{ register struct scsi_sm_reg *smr; register struct sm_snap *smsnap = &smreg_info; register struct udc_table *dvma; register int i, s; u_long toutcnt; u_char espstat; /* get to scsi control logic registers */ smr = (struct scsi_sm_reg *)h_sip->devaddr; dvma = (struct udc_table *)h_sip->dmaaddr; s = dvma->ctl_stat; DPRINTF1("sm_intr: dma_stat: %x\n", s); /* check dvma's req_pend, err_pend, and int_pend */ /* should only have int_pend set, if NO error */ if ((s & DVMA_INT_MASK) == ZERO) { DPRINTF1("sm_intr: DVMA *NO* int_pend, stat: %x\n", s); goto INTR_CHK_ERR; } /* Do not read ESP reg_interrupt before reading status and step reg */ /* after reading ESP reg_interrupt, ESP's INT will get cleared */ smsnap->esp_step = ESP_RD.step; smsnap->esp_stat = ESP_RD.stat; espstat = smsnap->esp_stat; smsnap->esp_intr = ESP_RD.intr; /* clear INT */ DPRINTF2("sm_intr: state= %x, int= %x\n", smsnap->cur_state, smsnap->esp_intr); DPRINTF2("sm_intr: step= %x, stat= %x\n", smsnap->esp_step, espstat); if (smsnap->cur_state == STATE_DATA_REQ) { s = dvma->ctl_stat; DPRINTF1("sm_intr: dma_stat: %x\n", s); smsnap->cur_retry++; if (s & DVMA_CHK_MASK) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -