📄 ncr.c
字号:
return (ACTION_CONTINUE); } else { return (ACTION_RETURN); }}static intncr_recvstatus(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register int amt, maxsb, action; maxsb = (((u_int) sp->cmd_pkt.pkt_scbp) + sp->cmd_scblen) - ((u_int) sp->cmd_scbp); if (maxsb <= 0) { printf("%s%d: status overrun\n", CNAME, CNUM); /* * XXX: reset bus */ sp->cmd_pkt.pkt_reason = CMD_STS_OVR; return (ACTION_FINISH); } if (NON_INTR(sp)) { amt = ncr_xfrin(ncr, PHASE_STATUS, sp->cmd_scbp, maxsb); if (amt <= 0) { return (ACTION_ABORT); } PRINTF3("ncr_recvstatus: status= %x\n", *sp->cmd_scbp); sp->cmd_scbp += amt; UPDATE_STATE(ACTS_UNKNOWN); action = ACTION_CONTINUE; } else { if (ncr_xfrin_noack(ncr, PHASE_STATUS, sp->cmd_scbp)) { return (ACTION_ABORT); } PRINTF3("ncr_recvstatus: status= %x\n", *sp->cmd_scbp); sp->cmd_scbp += amt; N_SBC->tcr = TCR_UNSPECIFIED; amt = N_SBC->clr; N_SBC->icr |= NCR_ICR_ACK; if (!REQ_DROPPED(ncr)) { return (ACTION_ABORT); } N_SBC->mr |= NCR_MR_DMA; N_SBC->icr = 0; if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); action = ACTION_RETURN; } UPDATE_STATE(ACTS_UNKNOWN); return (action);}/* * Utility Functions *//* * Perform Arbitration and SCSI selection * * input: (struct ncr) *ncr= pointer to a ncr software structure; * return: (int) SEL_TRUE = target arb/selected successful; * (int) SEL_ARBFAIL = Arbitration failed (bus busy) * (int) SEL_FALSE = selection timed out * (int) SEL_RESEL = Reselection attempt underway *//* local defines */#define WON_ARB (((sbc->icr & NCR_ICR_LA) == 0) && ((CDR & ~binid) < binid))static intncr_select(ncr)struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register struct ncrsbc *sbc = ncr->n_sbc; register int s, rval, retry; u_char uctmp; u_char binid = NUM_TO_BIT(ncr->n_id); PRINTF3("ncr_select: ready to do ARB/SEL for tgt %d\n", Tgt(sp)); if (INTPENDING(ncr)) { if (ncr_debug > 2) { ncr_printstate(ncr); printf("ncr_select: preempting\n"); } return (SEL_RESEL); } if (ncr->n_type != IS_3_50) DISABLE_DMA(ncr); if (ncr_debug > 1) ncr_printstate(ncr); /* * Attempt to arbitrate for the SCSI bus. * * It seems that the tcr must be 0 for arbitration to work. */ sbc->tcr = 0; sbc->mr &= ~NCR_MR_ARB; /* turn off arb */ sbc->icr = 0; sbc->odr = binid; UPDATE_STATE(STATE_ARBITRATION); rval = SEL_ARBFAIL; for (retry = 0; retry < NCR_ARB_RETRIES; retry++) { /* wait for scsi bus to become free */ if (ncr_sbcwait(&CBSR, NCR_CBSR_BSY, NCR_WAIT_COUNT, 0)) { PRINTF3("%s%d: scsi bus continuously busy, cbsr= %x\n", CNAME, CNUM, sbc->cbsr); break; } PRINTF3("ncr_select: bus free, current cbsr= %x\n", CBSR); /* * If the bus is now FREE, turn on ARBitration */ sbc->mr |= NCR_MR_ARB; /* * wait for ncr to begin arbitration by calling ncr_sbcwait(). * If failed due to reselection, turn off ARB, preempt the job * and return SEL_RESEL. */ if (ncr_sbcwait(&sbc->icr, NCR_ICR_AIP, NCR_ARB_WAIT, 1)) { /* * sbc may never begin arbitration * due to a target reselecting us. * (time critical) */ s = splhigh(); sbc->mr &= ~NCR_MR_ARB; /* turn off arb */ if (RESELECTING(CBSR, CDR, binid)) { (void) splx(s); rval = SEL_RESEL; break; } (void) splx(s); printf ("%s%d: AIP never set, cbsr= 0x%x\n", CNAME, CNUM, CBSR); } else { /* * check to see if we won arbitration * (time critical) */ s = splhigh(); DELAY(ncr_arbitration_delay); if (WON_ARB) { (void) splx(s); rval = SEL_FALSE; break; } (void) splx(s); } PRINTF3("ncr_select: lost_arb, current cbsr= %x\n", CBSR); /* * Lost arbitration. Maybe try again in a nano or two * (time critical) */ s = splhigh(); sbc->mr &= ~NCR_MR_ARB; /* turn off ARB */ if (RESELECTING(CBSR, CDR, binid)) { (void) splx(s); rval = SEL_RESEL; break; } (void) splx(s); } if (rval == SEL_ARBFAIL) { /* * FAILED ARBITRATION even with retries. * This shouldn't happen since we (usually) * have the highest priority id on the scsi bus. */ sbc->icr = 0; sbc->mr = 0; uctmp = sbc->clr; /* * After exhausting retries, and if there * are any outstanding disconnected cmds, * enable reselection attempts from them * and return SEL_FALSE. * */ PRINTF3("ncr_select: failed arb, target= %x\n", Tgt(sp)); if (ncr->n_ndisc > 0) { sbc->ser = 0; sbc->ser = binid; if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); } return (rval); } else if (rval == SEL_RESEL) { sbc->mr = 0; if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); return (rval); } /* * Okay. We got the bus. Now attempt to select the target. */#ifdef DO_NOT_DO_THIS_HERE /* * Don't mark that we got the bus yet, because * we may in fact have *not* got it (see below) */ sp->cmd_pkt.pkt_state |= STATE_GOT_BUS;#endif /* * XXX: ??? */ sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE; UPDATE_STATE(STATE_SELECTING); /* * calculate binary of target_id and host_id * and or them together to send out. */ uctmp = ((1 << Tgt(sp)) | binid); sbc->odr = uctmp; uctmp = (NCR_ICR_SEL | NCR_ICR_BUSY | NCR_ICR_DATA); if ((scsi_options & SCSI_OPTIONS_DR) && (sp->cmd_pkt.pkt_flags & FLAG_NODISCON) == 0) { ncr->n_cur_msgout[0] = MSG_DR_IDENTIFY | Lun (sp); ncr->n_omsglen = 1; ncr->n_omsgidx = 0; uctmp |= NCR_ICR_ATN; } sbc->icr = uctmp; /* start selection */ sbc->mr &= ~NCR_MR_ARB; /* turn off arb */ DELAY(ncr_bus_clear_delay + ncr_bus_settle_delay); /* * Drop our assertion of BSY* (left on during arbitration) */ sbc->icr &= ~NCR_ICR_BUSY; DELAY(1); /* * Apparently the ncr chip lies about actually * getting the bus, hence we'll check for a reselection * attempt here. */ for (retry = 0; retry < NCR_SHORT_WAIT; retry ++) { /* * If BSY asserted, then the target has selected. * If not, check for a reselection attempt. */ if (CBSR & NCR_CBSR_BSY) { PRINTF3("ncr_select: cbsr= 0x%b\n", CBSR, cbsr_bits); break; } else if (RESELECTING(CBSR, CDR, binid)) { sbc->mr = 0; sbc->icr = 0; if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); PRINTF3("ncr_select: arb_won, but preempt again\n"); return (SEL_RESEL); } DELAY(10); } /* * Say that we got the bus here rather than earlier. */ sp->cmd_pkt.pkt_state |= STATE_GOT_BUS; if (retry >= NCR_SHORT_WAIT) { /* * Target failed selection */ sbc->icr = 0; sbc->mr = 0; uctmp = sbc->clr; /* * if failed to select target, enable disconnect, * if any discon_job pending */ if (ncr->n_ndisc > 0) { sbc->ser = 0; sbc->ser = binid; if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); } sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE; return (SEL_FALSE); } /* * Drop SEL* and DATA* */ sbc->tcr = TCR_UNSPECIFIED; if (!NON_INTR(sp)) { /* * Time critical */ s = splhigh(); if (sp->cmd_flags & CFLAG_DMAVALID) { (*ncr->n_dma_setup)(ncr); } sbc->mr |= NCR_MR_DMA; sbc->icr &= ~(NCR_ICR_SEL | NCR_ICR_DATA); (void) splx(s); if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); } else { if (sp->cmd_flags & CFLAG_DMAVALID) { (*ncr->n_dma_setup)(ncr); } sbc->icr &= ~(NCR_ICR_SEL | NCR_ICR_DATA); } /* * Flag that we have selected the target... */ sp->cmd_pkt.pkt_state |= STATE_GOT_TARGET; UPDATE_STATE(STATE_SELECTED); PRINTF3("ncr_select: select ok\n"); return (SEL_TRUE);}static voidncr_preempt(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); UPDATE_STATE(STATE_FREE); UPDATE_SLOT(UNDEFINED); ncr->n_preempt++; if (NON_INTR(sp) && INTPENDING(ncr)) { ncrsvc(ncr); }}static voidncr_disconnect(ncr)struct ncr *ncr;{ struct scsi_cmd *sp = CURRENT_CMD(ncr); sp->cmd_pkt.pkt_statistics |= STAT_DISCON; sp->cmd_flags |= CFLAG_CMDDISC; ncr->n_ndisc++; ncr->n_last_slot = ncr->n_cur_slot; ncr->n_cur_slot = UNDEFINED; ncr->n_lastcount = 0; ncr->n_disconnects++; ncr->n_omsglen = ncr->n_omsgidx = 0; ncr->n_last_msgin = 0xff; UPDATE_STATE(STATE_FREE); if (NON_INTR(sp) == 0) { short nextslot; nextslot = Tgt(sp) + NLUNS_PER_TARGET; if (nextslot >= NLUNS_PER_TARGET*NTARGETS) nextslot = 0; (void) ncr_ustart(ncr, nextslot); }}/* * Programmed I/O Routines */static intncr_xfrin(ncr, phase, datap, amt) /* pick up incoming data byte(s) */register struct ncr *ncr;int phase;register caddr_t datap;register int amt;{ register int i, s; register struct ncrsbc *sbc = N_SBC; register u_char icr; PRINTF3("ncr_xfrin: amt= %x\n", amt); /* * Get data from the scsi bus. */ if ((sbc->cbsr & NCR_CBSR_REQ) == 0) { sbc->tcr = TCR_UNSPECIFIED; EPRINTF("ncr_xfrin: bad REQ, cbsr= 0x%b\n", CBSR, cbsr_bits); return (FAILURE); } else if ((sbc->bsr & NCR_BSR_PMTCH) == 0) { sbc->tcr = TCR_UNSPECIFIED; EPRINTF("ncr_xfrin: bad bus match, bsr= %x\n", sbc->bsr); return (FAILURE); } for (i = 0; i < amt; i++) { /* wait for target request */ if (i && !REQ_ASSERTED(ncr)) { sbc->tcr = TCR_UNSPECIFIED; return (FAILURE); } if (i && (sbc->bsr & NCR_BSR_PMTCH) == 0) { /* * phase is not matched. Check to * see whether we should match it */ if ((sbc->cbsr & (0x7<<2)) == phase) sbc->tcr = phase >> 2; else break; } /* grab data and complete req/ack handshake */ *datap++ = sbc->cdr; s = splhigh(); sbc->icr |= NCR_ICR_ACK; sbc->tcr = TCR_UNSPECIFIED; (void) splx(s); if (!REQ_DROPPED(ncr)) { EPRINTF("ncr_xfrin: REQ not dropped, cbsr=0x%b\n", CBSR, cbsr_bits); sbc->icr = 0; return (FAILURE); } /* Drop acknowledgement... */ sbc->icr = 0; } sbc->tcr = TCR_UNSPECIFIED; sbc->icr = 0; /* duplicate */ PRINTF3("ncr_xfrin: picked up %d\n", i); return (i);}static intncr_xfrin_noack(ncr, phase, datap)register struct ncr *ncr;int phase;caddr_t datap;{ register u_char indata; PRINTF3("ncr_xfrin_noack: phase= %x\n", phase); if ((N_SBC->cbsr & NCR_CBSR_REQ) == 0) { N_SBC->tcr = TCR_UNSPECIFIED; EPRINTF("ncr_xfrin_noack: bad REQ, cbsr=0x%b\n", CBSR, cbsr_bits); return (FAILURE); } else if ((N_SBC->bsr & NCR_BSR_PMTCH) == 0) { N_SBC->tcr = TCR_UNSPECIFIED; return (FAILURE); } /* * Get data from the scsi bus, but NO acknowlegment; if current phase * is MESSAGE_IN, clear TCR */ indata = N_SBC->cdr; if (phase == PHASE_MSG_IN) { /* * We've picked up the message byte, but not acknowledged it * yet. Perhaps here is the best place to clear the tcr * register in the case that a COMMAND COMPLETE or a * DISCONNECT message was just sent and the target is gonna * clear the SCSI bus just as soon as it is acknowledged. We * have to have tcr 0 to recognize other targets then * attempting to reselect us... */ N_SBC->tcr = 0; } *datap = indata; PRINTF3("ncr_xfrin_noack: indata= %x\n", indata); return (SUCCESS);}/* * Dma Subroutines */#ifdef sun4static intncr_cobra_dma_chkerr(ncr, bcr) /* check for any DMA error */register struct ncr *ncr;u_int bcr;{ struct scsi_cmd *sp = CURRENT_CMD(ncr); u_int csr; csr = GET_CSR(ncr); PRINTF3("ncr_dma_chkerr: csr= %x, bcr= %x\n", csr, bcr); /* check any abormal DMA conditions */ if (csr & NCR_CSR_DMA_CONFLICT) { EPRINTF("ncr_dma_cleanup: dma conflict\n"); return (FAILURE); } else if (csr & NCR_CSR_DMA_BUS_ERR) { /* * Note from sw.c: * * Early Cobra units have a faulty gate array. It can cause an * illegal memory access if full page DMA is being used. For * less than a full page, no problem. This problem typically * shows up when dumping core (in polled mode) where the last * page of DVMA was being used. * * What this means is that if you camp on the dma gate array * csr in polled mode, the ncr chip may attempt to prefetch * across a page boundary into an invalid page, causing a * spurious DMA error. */ if (!((ncr->n_type == IS_COBRA) && (bcr > 2) && NON_INTR(sp))) { EPRINTF("ncr_dma_chkerr: dma bus error\n"); return (FAILURE); } } return (SUCCESS);}static intncr_cobra_dma_recv(ncr)register struct ncr *ncr;{ register u_long addr, offset, bpr; /* * if partial bytes left on the dma longword transfers, manually take * care of this and return back how many bytes moved */ /* * 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. * * Note: limiting dma address to 20 bits (1 mb). * */ addr = GET_DMA_ADDR(ncr); addr &= 0xfffff; offset = addr & ~3; bpr = GET_BPR(ncr); switch (addr & 0x3) { case 3: if (ncr_flushbyte(ncr, offset+2, (u_char) ((bpr>>8)&0xff))) return (FAILURE); /* FALLTHROUGH */ case 2: if (ncr_flushbyte(ncr, offset+1, (u_char) ((bpr>>16)&0xff))) return (FAILURE); /* FALLTHROUGH */ case 1:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -