📄 esp.c
字号:
struct scsi_address *ap;char *cap;int val, tgtonly, doset;{ register struct esp *esp = (struct esp *) ap->a_cookie; register cidx; register u_char tshift = (1<<ap->a_target); register u_char ntshift = ~tshift; register rval = FALSE; if ((tgtonly != 0 && tgtonly != 1) || cap == (char *) 0) { return (rval); } for (cidx = 0; scsi_capstrings[cidx]; cidx++) { if (strcmp(cap, scsi_capstrings[cidx]) == 0) break; } if (scsi_capstrings[cidx] == (char *) 0) { rval = UNDEFINED; } else if (doset && (val == 0 || val == 1)) { /* * At present, we can only set binary (0/1) values */ switch (cidx) { case SCSI_CAP_DMA_MAX: case SCSI_CAP_MSG_OUT: case SCSI_CAP_PARITY: case SCSI_CAP_INITIATOR_ID: /* * None of these are settable via * the capability interface. */ break; case SCSI_CAP_DISCONNECT: if ((scsi_options & SCSI_OPTIONS_DR) == 0) { break; } else if (tgtonly) { if (val) esp->e_nodisc &= ntshift; else esp->e_nodisc |= tshift; } else { esp->e_nodisc = (val) ? 0 : 0xff; } rval = TRUE; break; case SCSI_CAP_SYNCHRONOUS: if ((scsi_options & SCSI_OPTIONS_SYNC) == 0) { break; } else if (tgtonly) { if (val) { esp->e_weak &= ntshift; } else { esp->e_weak |= tshift; } esp->e_sync_known &= ntshift; } else { if (val) { esp->e_weak = 0; } else { esp->e_weak = 0xff; } esp->e_sync_known = 0; } rval = TRUE; break; case SCSI_CAP_WIDE_XFER: case SCSI_CAP_UNTAGGED_QING: case SCSI_CAP_TAGGED_QING: default: rval = UNDEFINED; break; } } else if (doset == 0) { switch (cidx) { case SCSI_CAP_DMA_MAX: switch (DMAGA_REV(esp->e_dma)) { default: case DMA_REV1: case DMA_REV2: case ESC1_REV1: rval = 1<<24; break; case DMA_REV3: rval = 1<<30; break; } break; case SCSI_CAP_MSG_OUT: rval = TRUE; break; case SCSI_CAP_DISCONNECT: if ((scsi_options & SCSI_OPTIONS_DR) && (tgtonly == 0 || (esp->e_nodisc & tshift) == 0)) { rval = TRUE; } break; case SCSI_CAP_SYNCHRONOUS: if ((scsi_options & SCSI_OPTIONS_SYNC) && (tgtonly == 0 || esp->e_offset[ap->a_target])) { rval = TRUE; } break; case SCSI_CAP_PARITY: if (scsi_options & SCSI_OPTIONS_PARITY) rval = TRUE; break; case SCSI_CAP_INITIATOR_ID: rval = MY_ID(esp); break; default: rval = UNDEFINED; break; } } return (rval);}static intesp_getcap(ap, cap, whom)struct scsi_address *ap;char *cap;int whom;{ return (esp_commoncap(ap, cap, 0, whom, 0));}static intesp_setcap(ap, cap, value, whom)struct scsi_address *ap;char *cap;int value, whom;{ return (esp_commoncap(ap, cap, value, whom, 1));}/* * Internal Search Routine. * * Search for a command to start. */static intesp_ustart(esp, start_slot)register struct esp *esp;short start_slot;{ register struct scsi_cmd *sp; register short slot, found = 0; char dkn; if (start_slot == UNDEFINED) start_slot = 0; slot = start_slot; /* * If all commands queued up here are * disconnected, there is no work to do. * * e_ndisc should always be <= e_ncmds. * */ if (esp->e_ncmds <= esp->e_ndisc) { return (FALSE); } do { sp = esp->e_slots[slot]; if (sp && (sp->cmd_flags & CFLAG_CMDDISC) == 0) { found++; } else { slot = NEXTSLOT(slot); } } while (found == 0 && slot != start_slot); if (!found) { return (FALSE); } esp->e_cur_slot = slot; if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) { dk_busy |= (1<<dkn); dk_xfer[dkn]++; if ((sp->cmd_flags & CFLAG_DMASEND) == 0) dk_read[dkn]++; dk_wds[dkn] += sp->cmd_dmacount >> 6; } return (esp_startcmd(esp));}/* * Start a command off */static intesp_startcmd(esp)register struct esp *esp;{ register struct espreg *ep = esp->e_reg; register struct dmaga *dmar = esp->e_dma; register struct scsi_cmd *sp = CURRENT_CMD(esp); int legal_cmd_len, i; u_char cmd, nstate, tshift, target; register caddr_t tp = (caddr_t) esp->e_cmdarea; /* * The only reason that this should happen * is if we have a re-selection attempt starting. */ if (INTPENDING(esp)) { ESP_PREEMPT(esp); LOG_STATE(ACTS_PREEMPTED, esp->e_stat, Tgt(sp), Lun(sp)); (void) esp_poll(); return (FALSE); } esp->e_sdtr = esp->e_omsglen = 0; target = Tgt(sp); tshift = 1<<target;#ifdef ESPDEBUG esp->e_xfer = sp->cmd_dmacount;#endif /* ESPDEBUG */ /* * The ESP chip will only automatically * send 6, 10 or 12 byte SCSI cmds. */ switch (legal_cmd_len = sp->cmd_cdblen) { case CDB_GROUP0: case CDB_GROUP1: case CDB_GROUP5: break; default: legal_cmd_len = 0; break; } if (((esp->e_targets & tshift) == 0) || (esp->e_nodisc & tshift) || (sp->cmd_pkt.pkt_flags & FLAG_NODISCON) || (scsi_options & SCSI_OPTIONS_DR) == 0) { cmd = CMD_SEL_NOATN; nstate = STATE_SELECT_NOATN; } else { /* * Okay, we're at least going to send an identify message. */ *tp++ = MSG_DR_IDENTIFY | Lun(sp); if (sp->cmd_flags & CFLAG_CMDPROXY) { /* * This is a proxy command. It will have * a message to send as part of post-selection * (e.g, MSG_ABORT or MSG_DEVICE_RESET) */ /* * XXX: We should check to make sure that * this is a valid PROXY command, i.e, * a valid message length. */ esp->e_omsglen = sp->cmd_cdb[ESP_PROXY_DATA]; i = 0; while (i < esp->e_omsglen) { esp->e_cur_msgout[i] = sp->cmd_cdb[ESP_PROXY_DATA+1+i]; i++; } sp->cmd_cdb[ESP_PROXY_RESULT] = FALSE; cmd = CMD_SEL_STOP; nstate = STATE_SELECT_N_SENDMSG; legal_cmd_len = 0; LOG_STATE(ACTS_PROXY, esp->e_stat, esp->e_cur_msgout[0], nstate); } else if ((esp->e_sync_known & tshift) || (scsi_options & SCSI_OPTIONS_SYNC) == 0) { if (legal_cmd_len) { cmd = CMD_SEL_ATN; nstate = STATE_SELECT_NORMAL; } else { cmd = CMD_SEL_STOP; nstate = STATE_SELECT_N_STOP; } } else { /* * Set up to send an extended message after * we select and send the identify message. */ if (esp->e_weak & tshift) { esp_make_sdtr(esp, 0, 0); } else { esp_make_sdtr(esp, (int) esp->e_default_period, (int) DEFAULT_OFFSET); } legal_cmd_len = 0; cmd = CMD_SEL_STOP; nstate = STATE_SELECT_N_SENDMSG; LOG_STATE(ACTS_SYNCHOUT, esp->e_stat, esp->e_default_period, DEFAULT_OFFSET); /* * XXX: Set sync known here because the Sony CDrom * ignores the synch negotiation msg. Net effect * is we negotiate on every I/O request forever. */ esp->e_sync_known |= (1<<target); } } /* * If we are a ESP100A or a ESP236, and in SCSI-2 mode * we could also load another message here. */ /* * Now load cdb (if any) */ for (i = 0; i < legal_cmd_len; i++) { *tp++ = sp->cmd_cdbp[i]; } if (legal_cmd_len) { LOG_STATE(ACTS_CMD_START, esp->e_stat, sp->cmd_cdbp[0], nstate); } /* * calculate total dma amount: */ esp->e_lastcount = ((u_long) tp) - ((u_long) esp->e_cmdarea); /* * load rest of chip registers */ ep->esp_busid = target; ep->esp_sync_period = esp->e_period[target] & SYNC_PERIOD_MASK; ep->esp_sync_offset = esp->e_offset[target] | esp->e_req_ack_delay; if ((esp->e_type == FAS236) || (esp->e_type == FAS100A)) { ep->esp_conf3 = esp->e_espconf3[target]; } if ((scsi_options & SCSI_OPTIONS_PARITY) && (sp->cmd_pkt.pkt_flags & FLAG_NOPARITY)) { ep->esp_conf = esp->e_espconf & ~ESP_CONF_PAREN; } SET_ESP_COUNT(ep, esp->e_lastcount); if (DMAGA_REV(dmar) == ESC1_REV1) { SET_DMAESC_COUNT(dmar, esp->e_lastcount); } dmar->dmaga_addr = esp->e_lastdma = (((caddr_t)esp->e_cmdarea) - DVMA) | esp->e_dma_base; if (DMAGA_REV(dmar) == ESC1_REV1) { dmar->dmaga_csr |= (dmar->dmaga_csr & ~DMAGA_WRITE) | (DMAGA_INTEN|DMAGA_ENDVMA); } else { dmar->dmaga_csr = (dmar->dmaga_csr & ~DMAGA_WRITE) | (DMAGA_INTEN|DMAGA_ENDVMA); } if (dmar->dmaga_csr & DMAGA_INT_MASK) { ESP_PREEMPT(esp); LOG_STATE(ACTS_PREEMPTED, esp->e_stat, Tgt(sp), Lun(sp)); (void) esp_poll(); return (FALSE); } ep->esp_cmd = cmd | CMD_DMA; New_state(esp, nstate); LOG_STATE(nstate, esp->e_stat, target, Lun(sp));#ifdef ESPDEBUG if (DEBUGGING) { eprintf(esp, "sel %d.%d cmd[ ", target, Lun(sp)); for (i = 0; i < sp->cmd_cdblen; i++) printf("0x%x ", sp->cmd_cdbp[i]&0xff); printf("]\n\tstate=%s\n", esp_state_name(esp->e_state)); }#endif /* ESPDEBUG */ return (TRUE);}static intesp_link_start(esp)register struct esp *esp;{ esp->e_nlinked++; if ((esp->e_stat & ESP_PHASE_MASK) != ESP_PHASE_COMMAND) { esp->e_stat = esp->e_reg->esp_stat & ~ESP_STAT_RES; } if ((esp->e_stat & ESP_PHASE_MASK) != ESP_PHASE_COMMAND) { /* * XXX need a way to mark this particular failure */ esp_printstate(esp, "Linked command not in command phase"); /* * XXX: Needs to be 'soft' abort */ return (ACTION_ABORT_CURCMD); } /* * we'll let esp_phasemanage do the dirty work from here on out... */ New_state(esp, ACTS_CMD_START); return (ACTION_PHASEMANAGE);}/* * Finish routines */static intesp_finish(esp)register struct esp *esp;{ short last_slot; register int span_states = 0; register struct scsi_cmd *sp = CURRENT_CMD(esp); register action; char dkn; if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) { dk_busy &= ~(1<<dkn); } last_slot = esp->e_last_slot = esp->e_cur_slot; esp->e_cur_slot = UNDEFINED; esp->e_ncmds -= 1;#ifdef ESPDEBUG if (DEBUGGING) { eprintf(esp, "%d.%d; cmds=%d disc=%d npoll=%d; lastmsg 0x%x\n", Tgt(sp), Lun(sp), esp->e_ncmds, esp->e_ndisc, esp->e_npolling, esp->e_last_msgin); printf("\treason '%s'; cmd state 0x%b\n", scsi_rname(sp->cmd_pkt.pkt_reason), sp->cmd_pkt.pkt_state, state_bits); }#endif /* ESPDEBUG */ if (esp->e_last_msgin == MSG_LINK_CMPLT || esp->e_last_msgin == MSG_LINK_CMPLT_FLAG) { span_states++; } /* * XXX: ELSE WE NEED TO SET SPAN_STATES FOR COMMANDS COMPLETING * XXX: WITH A CHECK CONDITION. */ if ((sp->cmd_pkt.pkt_state & STATE_GOT_STATUS) && ((struct scsi_status *) sp->cmd_pkt.pkt_scbp)->sts_chk) { /* * In the case that we are getting a check condition * clear our knowledge of synchronous capabilities. * This will unambiguously force a renegotiation * prior to any possible data transfer (we hope), * including the data transfer for a UNIT ATTENTION * condition generated by somebody powering on and * off a target. */ if (esp->e_offset[Tgt(sp)] != 0) { esp->e_sync_known &= ~(1<<Tgt(sp)); } } if (sp->cmd_pkt.pkt_state & STATE_XFERRED_DATA) { register struct dataseg *segtmp = sp->cmd_subseg.d_next; register i; /* * XXX : FIX ME NEED TO MERGE TOGETHER OVERLAPPING AND * XXX : ADJACENT SEGMENTS!!! */ if (segtmp != (struct dataseg *) 0 && segtmp->d_count) { panic("esp_finish: more than one segment with data"); /* NOTREACHED */ } /* * Walk through all data segments and count up transfer counts */ i = 0; segtmp = &sp->cmd_subseg; while (segtmp) { i += segtmp->d_count; segtmp = segtmp->d_next; } sp->cmd_pkt.pkt_resid = sp->cmd_dmacount - i;#ifdef ESPDEBUG if (INFORMATIVE && sp->cmd_pkt.pkt_resid) { eprintf(esp, "%d.%d finishes with %d resid\n", Tgt(sp), Lun(sp), sp->cmd_pkt.pkt_resid); }#endif /* ESPDEBUG */ } New_state(esp, STATE_FREE); esp->e_slots[last_slot] = (struct scsi_cmd *) 0; if (sp->cmd_pkt.pkt_flags & FLAG_NOINTR) { esp->e_npolling -= 1; (*sp->cmd_pkt.pkt_comp)(sp); action = ACTION_RETURN; } else if (span_states > 0) { /* * If we're going to start a linked command, * hold open the state of the host adapter... */ esp->e_state = ACTS_SPANNING; (*sp->cmd_pkt.pkt_comp)(sp); esp->e_state = STATE_FREE; /* * This is we can check upon return that * the target driver did the right thing... * * If the target driver didn't do the right * thing, we have to abort the operation. */ if (esp->e_slots[last_slot] == 0) { /* * XXX: HERE IS WHERE WE NEED A PROXY COMMAND IN * XXX: IN ORDER TO SEND AN ABORT OPERATION MESSAGE * XXX: TO THE TARGET!!! */ esplog(esp, LOG_ERR,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -