📄 ncr.c
字号:
return (FAILURE); } /* * We respond by dropping our assertion of BSY* */ N_SBC->icr &= ~NCR_ICR_BUSY; N_SBC->tcr = TCR_UNSPECIFIED; N_SBC->ser = 0; /* clear int */ N_SBC->ser = binary_id; /* enable (re)sel int */ UPDATE_STATE(STATE_RESELECT); if (ncr_getphase(ncr) != ACTION_CONTINUE) { printf("%s%d: no REQ during reselect\n", CNAME, CNUM); return (FAILURE); } if (ncr->n_state != ACTS_MSG_IN) { printf("%s%d: reselect not followed by a MSG IN phase\n", CNAME, CNUM); return (FAILURE); } /* * Now pick up identify message byte, and acknowledge it. */ if (ncr_xfrin_noack(ncr, PHASE_MSG_IN, &msgin)) { printf("%s%d: can't get IDENTIFY message on reselect\n", CNAME, CNUM); return (FAILURE); } if ((msgin & MSG_IDENTIFY) == 0 || (msgin & (INI_CAN_DISCON|BAD_IDENTIFY))) { printf("%s%d: mangled identify message 0x%x\n", msgin); return (FAILURE); } lun = msgin & (NLUNS_PER_TARGET-1); /* * now search for lun to reconnect to */ lun &= (NLUNS_PER_TARGET-1); slot = (target * NLUNS_PER_TARGET) | lun; if (ncr->n_slots[slot] == 0) { printf("%s%d: Cannot Reconnect Lun %d on Target %d\n", CNAME, CNUM, lun, target); return (FAILURE); } ncr->n_cur_slot = slot; ncr->n_ndisc--; sp = CURRENT_CMD(ncr); /* * A reconnect implies a restore pointers operation */ sp->cmd_cdbp = sp->cmd_pkt.pkt_cdbp; sp->cmd_scbp = sp->cmd_pkt.pkt_scbp; sp->cmd_data = sp->cmd_saved_data; sp->cmd_flags &= ~CFLAG_CMDDISC; /* * and finally acknowledge the identify message */ ncr->n_last_msgin = msgin; UPDATE_STATE(ACTS_RESELECTING); if (ncr_ACKmsg(ncr)) { printf("%s%d: unable to acknowledge identify message\n", CNAME, CNUM); return (FAILURE); } return (SUCCESS);}/* * State Management Section *//* * manage phases on the SCSI bus * * We assume (on entry) that we are connected to a * target and that CURRENT_CMD(ncr) is valid. We * also assume that the phase is unknown. We continue * calling one of a set of phase management routines * until we either are going to return (to ncrsvc * or ncr_ustart()), or have to abort the command, * or are going to call ncr_finish() (to complete * this command), or are going to turn aroung and * call ncr_ustart() again to start another command. * */static voidncr_phasemanage(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register int i, action; /* * Important: The order of functions in this array *must* match * the defines in ncrreg.h with respect to the linear sequence * of states from ACTS_UNKNOWN thru ACTS_COMMAND. */ static int (*itvec[])() = { ncr_getphase, ncr_sendmsg, ncr_recvmsg, ncr_recvstatus, ncr_sendcmd, ncr_recvdata, ncr_senddata }; static char *itnames[] = { "unknown", "msg out", "msg in", "status", "cmd", "data in", "data out" }; action = ACTION_CONTINUE; do { i = ncr->n_state - ACTS_ITPHASE_BASE; PRINTF3("ncr_phasemanage: state = %s\n", itnames[i]); action = (*itvec[i])(ncr); } while (action == ACTION_CONTINUE); switch (action) { case ACTION_RETURN: break; case ACTION_ABORT: ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG); break; case ACTION_FINISH: ncr_finish(ncr); break; case ACTION_SEARCH: ncr_disconnect(ncr); break; }}static intncr_getphase(ncr)register struct ncr *ncr;{ register u_char cbsr; register int lim, phase; u_long usecs = 0; static char phasetab[8] = { ACTS_DATA_OUT, ACTS_DATA_IN, ACTS_COMMAND, ACTS_STATUS, -1, /* 4 is undefined */ -1, /* 5 is undefined */ ACTS_MSG_OUT, ACTS_MSG_IN }; usecs = 10000000; for (lim = 0; lim < usecs; lim++) { cbsr = N_SBC->cbsr; if ((cbsr & NCR_CBSR_BSY) == 0) { /* * Unexpected loss of busy! */ printf("%s%d: target dropped BSY*\n", CNAME, CNUM); ncr_printstate(ncr); return (ACTION_ABORT); } else if ((cbsr & NCR_CBSR_REQ) == 0) { /* * If REQ* is not asserted, than the phase bits * are not valid. Delay a few u-secs before checking * again.. */ DELAY(2); continue; } phase = (cbsr >> 2) & 0x7; PRINTF3("ncr_getphase: phase= 0x%x\n", phase); if (phasetab[phase] == -1) { printf("%s%d: garbage phase. CBSR = 0x%b\n", CNAME, CNUM, cbsr, cbsr_bits); return (ACTION_ABORT); } /* * Note that if the phase is a data phase, we don't attempt * to match it. We leave that action to the discretion of the * dma routines. */ if (phase > 1 && (N_SBC->bsr & NCR_BSR_PMTCH) == 0) { N_SBC->tcr = phase; } UPDATE_STATE(phasetab[phase]); return (ACTION_CONTINUE); } printf("%s%d: REQ* never set\n", CNAME, CNUM); return (ACTION_ABORT);}/* * Send command bytes out the SCSI bus. REQ* should be asserted for us * to get here, and the phase should already be matched in the tcr register * (i.e., ncr_getphase() has done the right thing for us already). * * If this is a non-interrupting command, we should actually be able to * set up for a phase-mismatch interrupt after sending the command. * */static intncr_sendcmd(ncr)register struct ncr *ncr;{ register u_char junk; register struct ncrsbc *sbc = N_SBC; register int s, nonintr; struct scsi_cmd *sp = CURRENT_CMD(ncr); nonintr = (NON_INTR(sp) ? 1: 0); /* * We send a single byte of a command out here. * We could probably check to see whether REQ* is * asserted quickly again here, rather than awaiting * it in ncr_getphase() (for non-interrupting commands) * or spotting it in either ncrpoll() or ncrintr(). * * XXX: We should check for command overflow here! */ sbc->odr = *(sp->cmd_cdbp++); /* load data */ sbc->icr = NCR_ICR_DATA; /* enable sbc to send data */ /* * complete req/ack handshake */ s = splhigh(); sbc->icr |= NCR_ICR_ACK; sbc->tcr = TCR_UNSPECIFIED; (void) splx(s); if (!REQ_DROPPED(ncr)) { EPRINTF("ncr_sendcmd: REQ not dropped, cbsr=0x%b\n", CBSR, cbsr_bits); sbc->icr = 0; return (ACTION_ABORT); } if (nonintr == 0) { sbc->mr |= NCR_MR_DMA; junk = sbc->clr; } sbc->icr = 0; /* clear ack */ sp->cmd_pkt.pkt_state |= STATE_SENT_CMD; UPDATE_STATE(ACTS_UNKNOWN); if (nonintr) { return (ACTION_CONTINUE); } else { if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); return (ACTION_RETURN); }}/* * Send out a message. We assume on entry that phase is matched in the tcr * register of the SBC, and that REQ* has been asserted by the target (i.e., * ncr_getphase() has done the right thing). * * If this is a non-interrupting command, set up to get a phase-mismatch * interrupt on the next assertion of REQ* by the target. * */static intncr_sendmsg(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register struct ncrsbc *sbc = N_SBC; u_char junk; register s, nonintr; nonintr = (NON_INTR(sp) ? 1: 0); if (ncr->n_omsglen == 0 || ncr->n_omsgidx >= ncr->n_omsglen) { /* * No message to send or previous message exhausted. * Send a NO-OP message instead. */ printf("%s%d: unexpected message out phase for target %d\n", CNAME, CNUM, Tgt(sp)); ncr->n_omsglen = 1; ncr->n_omsgidx = 0; ncr->n_cur_msgout[0] = MSG_NOP; } if (ncr->n_omsgidx == 0) { ncr->n_last_msgout = ncr->n_cur_msgout[0]; } /* * load data */ PRINTF3("ncr_sendmsg: sending msg byte %d = 0x%x of %d len msg\n", ncr->n_omsgidx, ncr->n_cur_msgout[ncr->n_omsgidx], ncr->n_omsglen); sbc->odr = ncr->n_cur_msgout[ncr->n_omsgidx++]; sbc->icr |= NCR_ICR_DATA; if (ncr->n_omsgidx >= ncr->n_omsglen) { ncr->n_omsgidx = ncr->n_omsglen = 0; sbc->icr &= ~NCR_ICR_ATN; } /* * complete req/ack handshake */ s = splhigh(); sbc->icr |= NCR_ICR_ACK; sbc->tcr = TCR_UNSPECIFIED; (void) splx(s); if (!REQ_DROPPED(ncr)) { sbc->icr = 0; return (ACTION_ABORT); } if (nonintr == 0) { sbc->mr |= NCR_MR_DMA; junk = sbc->clr; } /* * Deassert ACK*. Note that this uses a mask-equal-not instead of * a straight clear because we may wish to leave ATN* asserted. */ junk = sbc->icr & (NCR_ICR_ACK|NCR_ICR_DATA|NCR_ICR_ATN); junk &= ~(NCR_ICR_ACK|NCR_ICR_DATA); sbc->icr = junk; UPDATE_STATE(ACTS_UNKNOWN); if (nonintr) { return (ACTION_CONTINUE); } else { if (ncr->n_type != IS_3_50) ENABLE_DMA(ncr); return (ACTION_RETURN); }}static intncr_recvmsg(ncr)register struct ncr *ncr;{ auto u_char msgin; register struct scsi_cmd *sp = CURRENT_CMD(ncr); static char *messages[] = { "Command Complete", "Extended Message", "Save Data Pointer", "Restore Pointers", "Disconnect", "Initiator Detected Error", "Abort", "No-op", "Message Reject", "Message Parity Error", "Linked Command Complete", "Linked Command Complete (w/flag)", "Bus Device Reset" }; /* * Pick up a message byte from the SCSI bus. Delay giving an ack * until we know if we can handle this message- that way we can * assert the ATN line before the ACK so that the target knows we are * gonna reject this message. */ if (ncr_xfrin_noack(ncr, PHASE_MSG_IN, &msgin)) { return (ACTION_ABORT); } else ncr->n_last_msgin = msgin; if (msgin & MSG_IDENTIFY) { /* * We shouldn't be getting an identify message here. */ printf("%s%d: out of sequence identify message: 0x%x\n", CNAME, CNUM, msgin); if (ncr_ACKmsg(ncr)) { return (ACTION_ABORT); } UPDATE_STATE(ACTS_UNKNOWN); return (ACTION_CONTINUE); } if (ncr_debug > 2) { if (msgin <= MSG_DEVICE_RESET) { printf("%s%d: msg=%s\n", CNAME, CNUM, messages[msgin]); } else { printf("%s%d: msg=0x%x\n", CNAME, CNUM, msgin); } } switch (msgin) { case MSG_DISCONNECT: /* * Important! Set state *before calling ncr_ACKmsg() * because ncr_ACKmsg() bases some actions on the * new state! */ UPDATE_STATE(ACTS_CLEARING_DISC); if (ncr_ACKmsg(ncr)) { return (ACTION_ABORT); } return (ACTION_SEARCH); case MSG_LINK_CMPLT: case MSG_LINK_CMPLT_FLAG: case MSG_COMMAND_COMPLETE: { /* * Note well that we *do NOT* ACK the message if it * is a LINKED COMMAND COMPLETE or LINKED COMMAND * COMPLETE (with flag) message. We leave that for * ncr_finish() to do once the target driver has * given us the next command to send. This is so * that the DMA engine can be set up for the new * command prior to ACKing this message. */ /* * Important! Set state *before calling ncr_ACKmsg() * because ncr_ACKmsg() bases some actions on the * new state! */ sp->cmd_pkt.pkt_reason = CMD_CMPLT; if (msgin == MSG_COMMAND_COMPLETE) { UPDATE_STATE(ACTS_CLEARING_DONE); if (ncr_ACKmsg(ncr)) { return (ACTION_ABORT); } } else { UPDATE_STATE(ACTS_UNKNOWN); } return (ACTION_FINISH); } case MSG_SAVE_DATA_PTR: sp->cmd_saved_data = (int) sp->cmd_data; break; case MSG_RESTORE_PTRS: sp->cmd_cdbp = sp->cmd_pkt.pkt_cdbp; sp->cmd_scbp = sp->cmd_pkt.pkt_scbp; if (sp->cmd_data != sp->cmd_saved_data) { sp->cmd_data = sp->cmd_saved_data; sp->cmd_flags |= CFLAG_NEEDSEG; PRINTF3("%s%d: %d.%d needs new data segment\n", CNAME, CNUM, Tgt(sp), Lun(sp)); } break; case MSG_NOP: break; default: if (ncr_NACKmsg(ncr)) { return (ACTION_ABORT); } UPDATE_STATE(ACTS_UNKNOWN); return (ACTION_CONTINUE); } if (ncr_ACKmsg(ncr)) { return (ACTION_ABORT); } UPDATE_STATE(ACTS_UNKNOWN); return (ACTION_CONTINUE);}/* * Enable DMA. If this is a non-interrupting command, await for DMA completion. */static intncr_senddata(ncr)register struct ncr *ncr;{ struct scsi_cmd *sp = CURRENT_CMD(ncr); register int reqamt; reqamt = ncr->n_lastcount; PRINTF3("ncr_senddata:\n", reqamt); if ((sp->cmd_flags & CFLAG_DMASEND) == 0) { printf("%s%d: unwanted data out phase\n", CNAME, CNUM); return (ACTION_ABORT); } if (reqamt == -1) { /* * XXXX */ printf("%s%d: odd byte dma send\n", CNAME, CNUM); return (ACTION_ABORT); } if (reqamt == 0) { ncr_dump_datasegs(sp); panic("ncr_senddata: no data to send\n"); } ncr_dma_enable(ncr, 0); /* 0 = send */ if (NON_INTR(sp)) { if (ncr_dma_wait(ncr)) { printf("%s%d: wait for dma timed out\n", CNAME, CNUM); return (ACTION_ABORT); } sp->cmd_pkt.pkt_state |= STATE_XFERRED_DATA; UPDATE_STATE(ACTS_UNKNOWN); return (ACTION_CONTINUE); } else { return (ACTION_RETURN); }}/* * Enable DMA. If this is a non-interrupting command, await for DMA completion. */static intncr_recvdata(ncr)register struct ncr *ncr;{ register struct scsi_cmd *sp = CURRENT_CMD(ncr); register reqamt; if (sp->cmd_flags & CFLAG_DMASEND) { printf("%s%d: unwanted data in phase\n", CNAME, CNUM); return (ACTION_ABORT); } reqamt = ncr->n_lastcount; if (reqamt == -1) { /* * XXXX */ printf("%s%d: odd byte dma send\n", CNAME, CNUM); return (ACTION_ABORT); } if (reqamt == 0) { panic("ncr_rcvdata: no place to put data"); /* NOTREACHED */ } ncr_dma_enable(ncr, 1); /* 1 = recv */ if (NON_INTR(sp)) { if (ncr_dma_wait(ncr)) { printf("%s%d: wait for dma timed out\n", CNAME, CNUM); return (ACTION_ABORT); } sp->cmd_pkt.pkt_state |= STATE_XFERRED_DATA; UPDATE_STATE(ACTS_UNKNOWN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -