📄 ncr53c9x.c
字号:
this = (Scsi_Cmnd *) this->host_scribble) { if(this == SCptr) { *prev = (Scsi_Cmnd *) this->host_scribble; this->host_scribble = NULL; esp_release_dmabufs(esp, this); this->result = DID_ABORT << 16; this->done(this); if(don) esp->dma_ints_on(esp); return SCSI_ABORT_SUCCESS; } } } /* Yuck, the command to abort is disconnected, it is not * worth trying to abort it now if something else is live * on the bus at this time. So, we let the SCSI code wait * a little bit and try again later. */ if(esp->current_SC) { if(don) esp->dma_ints_on(esp); return SCSI_ABORT_BUSY; } /* It's disconnected, we have to reconnect to re-establish * the nexus and tell the device to abort. However, we really * cannot 'reconnect' per se, therefore we tell the upper layer * the safest thing we can. This is, wait a bit, if nothing * happens, we are really hung so reset the bus. */ if(don) esp->dma_ints_on(esp); return SCSI_ABORT_SNOOZE;}/* We've sent ESP_CMD_RS to the ESP, the interrupt had just * arrived indicating the end of the SCSI bus reset. Our job * is to clean out the command queues and begin re-execution * of SCSI commands once more. */static int esp_finish_reset(struct NCR_ESP *esp, struct ESP_regs *eregs){ Scsi_Cmnd *sp = esp->current_SC; /* Clean up currently executing command, if any. */ if (sp != NULL) { esp_release_dmabufs(esp, sp); sp->result = (DID_RESET << 16); sp->scsi_done(sp); esp->current_SC = NULL; } /* Clean up disconnected queue, they have been invalidated * by the bus reset. */ if (esp->disconnected_SC) { while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { esp_release_dmabufs(esp, sp); sp->result = (DID_RESET << 16); sp->scsi_done(sp); } } /* SCSI bus reset is complete. */ esp->resetting_bus = 0; /* Ok, now it is safe to get commands going once more. */ if(esp->issue_SC) esp_exec_cmd(esp); return do_intr_end;}static int esp_do_resetbus(struct NCR_ESP *esp, struct ESP_regs *eregs){ ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); esp->resetting_bus = 1; esp_cmd(esp, eregs, ESP_CMD_RS); return do_intr_end;}/* Reset ESP chip, reset hanging bus, then kill active and * disconnected commands for targets without soft reset. */int esp_reset(Scsi_Cmnd *SCptr, unsigned int how){ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata; (void) esp_do_resetbus(esp, esp->eregs); return SCSI_RESET_PENDING;}/* Internal ESP done function. */static void esp_done(struct NCR_ESP *esp, int error){ Scsi_Cmnd *done_SC; if(esp->current_SC) { done_SC = esp->current_SC; esp->current_SC = NULL; esp_release_dmabufs(esp, done_SC); done_SC->result = error; done_SC->scsi_done(done_SC); /* Bus is free, issue any commands in the queue. */ if(esp->issue_SC && !esp->current_SC) esp_exec_cmd(esp); } else { /* Panic is safe as current_SC is null so we may still * be able to accept more commands to sync disk buffers. */ ESPLOG(("panicing\n")); panic("esp: done() called with NULL esp->current_SC"); }}/* Wheee, ESP interrupt engine. */ /* Forward declarations. */static int esp_do_phase_determine(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)/* We try to avoid some interrupts by jumping ahead and see if the ESP * has gotten far enough yet. Hence the following. */static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs, Scsi_Cmnd *scp, int prev_phase, int new_phase){ if(scp->SCp.sent_command != prev_phase) return 0; if(esp->dma_irq_p(esp)) { /* Yes, we are able to save an interrupt. */ esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); esp->ireg = esp_read(eregs->esp_intrpt); if(!(esp->ireg & ESP_INTR_SR)) return 0; else return do_reset_complete; } /* Ho hum, target is taking forever... */ scp->SCp.sent_command = new_phase; /* so we don't recurse... */ return do_intr_end;}static inline int skipahead2(struct NCR_ESP *esp, struct ESP_regs *eregs, Scsi_Cmnd *scp, int prev_phase1, int prev_phase2, int new_phase){ if(scp->SCp.sent_command != prev_phase1 && scp->SCp.sent_command != prev_phase2) return 0; if(esp->dma_irq_p(esp)) { /* Yes, we are able to save an interrupt. */ esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); esp->ireg = esp_read(eregs->esp_intrpt); if(!(esp->ireg & ESP_INTR_SR)) return 0; else return do_reset_complete; } /* Ho hum, target is taking forever... */ scp->SCp.sent_command = new_phase; /* so we don't recurse... */ return do_intr_end;}/* Misc. esp helper macros. */#define esp_setcount(__eregs, __cnt) \ esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \ esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))#define esp_getcount(__eregs) \ ((esp_read((__eregs)->esp_tclow)&0xff) | \ ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))#define fcount(__esp, __eregs) \ (esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)#define fnzero(__esp, __eregs) \ (esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO)/* XXX speculative nops unnecessary when continuing amidst a data phase * XXX even on esp100!!! another case of flooding the bus with I/O reg * XXX writes... */#define esp_maybe_nop(__esp, __eregs) \ if((__esp)->erev == esp100) \ esp_cmd((__esp), (__eregs), ESP_CMD_NULL)#define sreg_to_dataphase(__sreg) \ ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)/* The ESP100 when in synchronous data phase, can mistake a long final * REQ pulse from the target as an extra byte, it places whatever is on * the data lines into the fifo. For now, we will assume when this * happens that the target is a bit quirky and we don't want to * be talking synchronously to it anyways. Regardless, we need to * tell the ESP to eat the extraneous byte so that we can proceed * to the next phase. */static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs, Scsi_Cmnd *sp, int fifocnt){ /* Do not touch this piece of code. */ if((!(esp->erev == esp100)) || (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) && !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) { if(sp->SCp.phase == in_dataout) esp_cmd(esp, eregs, ESP_CMD_FLUSH); return 0; } else { /* Async mode for this guy. */ build_sync_nego_msg(esp, 0, 0); /* Ack the bogus byte, but set ATN first. */ esp_cmd(esp, eregs, ESP_CMD_SATN); esp_cmd(esp, eregs, ESP_CMD_MOK); return 1; }}/* This closes the window during a selection with a reselect pending, because * we use DMA for the selection process the FIFO should hold the correct * contents if we get reselected during this process. So we just need to * ack the possible illegal cmd interrupt pending on the esp100. */static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs){ volatile unchar junk; if(esp->erev != esp100) return 0; junk = esp_read(eregs->esp_intrpt); if(junk & ESP_INTR_SR) return 1; return 0;}/* This verifies the BUSID bits during a reselection so that we know which * target is talking to us. */static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs){ int it, me = esp->scsi_id_mask, targ = 0; if(2 != fcount(esp, eregs)) return -1; it = esp_read(eregs->esp_fdata); if(!(it & me)) return -1; it &= ~me; if(it & (it - 1)) return -1; while(!(it & 1)) targ++, it >>= 1; return targ;}/* This verifies the identify from the target so that we know which lun is * being reconnected. */static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs){ int lun; if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) return -1; lun = esp_read(eregs->esp_fdata); /* Yes, you read this correctly. We report lun of zero * if we see parity error. ESP reports parity error for * the lun byte, and this is the only way to hope to recover * because the target is connected. */ if(esp->sreg & ESP_STAT_PERR) return 0; /* Check for illegal bits being set in the lun. */ if((lun & 0x40) || !(lun & 0x80)) return -1; return lun & 7;}/* This puts the driver in a state where it can revitalize a command that * is being continued due to reselection. */static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs, Scsi_Cmnd *sp){ Scsi_Device *dp = sp->device; if(esp->prev_soff != dp->sync_max_offset || esp->prev_stp != dp->sync_min_period || (esp->erev > esp100a && esp->prev_cfg3 != esp->config3[sp->target])) { esp->prev_soff = dp->sync_max_offset; esp_write(eregs->esp_soff, esp->prev_soff); esp->prev_stp = dp->sync_min_period; esp_write(eregs->esp_stp, esp->prev_stp); if(esp->erev > esp100a) { esp->prev_cfg3 = esp->config3[sp->target]; esp_write(eregs->esp_cfg3, esp->prev_cfg3); } } esp->current_SC = sp;}/* This will place the current working command back into the issue queue * if we are to receive a reselection amidst a selection attempt. */static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp){ if(!esp->disconnected_SC) ESPLOG(("esp%d: Weird, being reselected but disconnected " "command queue is empty.\n", esp->esp_id)); esp->snip = 0; esp->current_SC = 0; sp->SCp.phase = not_issued; append_SC(&esp->issue_SC, sp);}/* Begin message in phase. */static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs){ esp_cmd(esp, eregs, ESP_CMD_FLUSH); esp_maybe_nop(esp, eregs); esp_cmd(esp, eregs, ESP_CMD_TI); esp->msgin_len = 1; esp->msgin_ctr = 0; esp_advance_phase(esp->current_SC, in_msgindone); return do_work_bus;}static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp){ ++sp->SCp.buffer; --sp->SCp.buffers_residual; sp->SCp.this_residual = sp->SCp.buffer->length; if (esp->dma_advance_sg) esp->dma_advance_sg (sp); else sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);}/* Please note that the way I've coded these routines is that I _always_ * check for a disconnect during any and all information transfer * phases. The SCSI standard states that the target _can_ cause a BUS * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note * that during information transfer phases the target controls every * change in phase, the only thing the initiator can do is "ask" for * a message out phase by driving ATN true. The target can, and sometimes * will, completely ignore this request so we cannot assume anything when * we try to force a message out phase to abort/reset a target. Most of * the time the target will eventually be nice and go to message out, so * we may have to hold on to our state about what we want to tell the target * for some period of time. *//* I think I have things working here correctly. Even partial transfers * within a buffer or sub-buffer should not upset us at all no matter * how bad the target and/or ESP fucks things up. */static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs){ Scsi_Cmnd *SCptr = esp->current_SC; int thisphase, hmuch; ESPDATA(("esp_do_data: ")); esp_maybe_nop(esp, eregs); thisphase = sreg_to_dataphase(esp->sreg); esp_advance_phase(SCptr, thisphase); ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); hmuch = esp->dma_can_transfer(esp, SCptr); /* * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0 */ if (hmuch) { /* DMA */ /* * DMA */ ESPDATA(("hmuch<%d> ", hmuch)); esp->current_transfer_size = hmuch; esp_setcount(eregs, (esp->fas_premature_intr_workaround ? (hmuch + 0x40) : hmuch)); esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), hmuch, (thisphase == in_datain)); ESPDATA(("DMA|TI --> do_intr_end\n")); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); return do_intr_end; /* * end DMA */ } else { /* * PIO */ int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */ int fifocnt = 0; oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK; /* * polled transfer; ugly, can we make this happen in a DRQ * interrupt handler ?? * requires keeping track of state information in host or * command struct! * Problem: I've never seen a DRQ happen on Mac, not even * with ESP_CMD_DMA ... */ /* figure out how much needs to be transfered */ hmuch = SCptr->SCp.this_residual; ESPDATA(("hmuch<%d> pio ", hmuch)); esp->current_transfer_size = hmuch; /* tell the ESP ... */ esp_setcount(eregs, hmuch); /* loop */ while (hmuch) { int j, fifo_stuck = 0, newphase; unsigned long flags, timeout;#if 0 if ( i % 10 ) ESPDATA(("\r")); else ESPDATA(( /*"\n"*/ "\r"));#endif save_flags(flags);#if 0 cli();#endif if(thisphase == in_datain) { /* 'go' ... */ esp_cmd(esp, eregs, ESP_CMD_TI); /* wait for data */ timeout = 1000000; while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) udelay(2); if (timeout == 0) printk("DRQ datain timeout! \n"); newphase = esp->sreg & ESP_STAT_PMASK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -