📄 esp.c
字号:
spin_unlock_irqrestore(&esp->lock, flags); return SCSI_ABORT_PENDING; } /* If it is still in the issue queue then we can safely * call the completion routine and report abort success. */ don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB); if (don) { ESP_INTSOFF(esp->dregs); } if (esp->issue_SC) { Scsi_Cmnd **prev, *this; for (prev = (&esp->issue_SC), this = esp->issue_SC; this != NULL; prev = (Scsi_Cmnd **) &(this->host_scribble), this = (Scsi_Cmnd *) this->host_scribble) { if (this == SCptr) { *prev = (Scsi_Cmnd *) this->host_scribble; this->host_scribble = NULL; spin_unlock_irqrestore(&esp->lock, flags); esp_release_dmabufs(esp, this); this->result = DID_ABORT << 16; this->scsi_done(this); if (don) ESP_INTSON(esp->dregs); 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_INTSON(esp->dregs); spin_unlock_irqrestore(&esp->lock, flags); 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_INTSON(esp->dregs); spin_unlock_irqrestore(&esp->lock, flags); 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 esp *esp){ Scsi_Cmnd *sp = esp->current_SC; /* Clean up currently executing command, if any. */ if (sp != NULL) { esp->current_SC = NULL; spin_unlock(&esp->lock); esp_release_dmabufs(esp, sp); sp->result = (DID_RESET << 16); spin_lock(&io_request_lock); sp->scsi_done(sp); spin_unlock(&io_request_lock); spin_lock(&esp->lock); } /* 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) { spin_unlock(&esp->lock); esp_release_dmabufs(esp, sp); sp->result = (DID_RESET << 16); spin_lock(&io_request_lock); sp->scsi_done(sp); spin_unlock(&io_request_lock); spin_lock(&esp->lock); } } /* 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 esp *esp){ ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); esp->resetting_bus = 1; esp_cmd(esp, 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 esp *esp = (struct esp *) SCptr->host->hostdata; unsigned long flags; spin_lock_irqsave(&esp->lock, flags); (void) esp_do_resetbus(esp); spin_unlock_irqrestore(&esp->lock, flags); return SCSI_RESET_PENDING;}/* Internal ESP done function. */static void esp_done(struct esp *esp, int error){ Scsi_Cmnd *done_SC = esp->current_SC; esp->current_SC = NULL; spin_unlock(&esp->lock); esp_release_dmabufs(esp, done_SC); done_SC->result = error; spin_lock(&io_request_lock); done_SC->scsi_done(done_SC); spin_unlock(&io_request_lock); /* Bus is free, issue any commands in the queue. */ spin_lock(&esp->lock); if (esp->issue_SC && !esp->current_SC) esp_exec_cmd(esp);}/* Wheee, ESP interrupt engine. */ /* Forward declarations. */static int esp_do_phase_determine(struct esp *esp);static int esp_do_data_finale(struct esp *esp);static int esp_select_complete(struct esp *esp);static int esp_do_status(struct esp *esp);static int esp_do_msgin(struct esp *esp);static int esp_do_msgindone(struct esp *esp);static int esp_do_msgout(struct esp *esp);static int esp_do_cmdbegin(struct esp *esp);#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)/* Read any bytes found in the FAS366 fifo, storing them into * the ESP driver software state structure. */static void hme_fifo_read(struct esp *esp){ u8 count = 0; u8 status = esp->sreg; /* Cannot safely frob the fifo for these following cases, but * we must always read the fifo when the reselect interrupt * is pending. */ if (((esp->ireg & ESP_INTR_RSEL) == 0) && (sreg_datainp(status) || sreg_dataoutp(status) || (esp->current_SC && esp->current_SC->SCp.phase == in_data_done))) { ESPHME(("<wkaround_skipped>")); } else { unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES; /* The HME stores bytes in multiples of 2 in the fifo. */ ESPHME(("hme_fifo[fcnt=%d", (int)fcnt)); while (fcnt) { esp->hme_fifo_workaround_buffer[count++] = sbus_readb(esp->eregs + ESP_FDATA); esp->hme_fifo_workaround_buffer[count++] = sbus_readb(esp->eregs + ESP_FDATA); ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1])); fcnt--; } if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) { ESPHME(("<poke_byte>")); sbus_writeb(0, esp->eregs + ESP_FDATA); esp->hme_fifo_workaround_buffer[count++] = sbus_readb(esp->eregs + ESP_FDATA); ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1])); ESPHME(("CMD_FLUSH")); esp_cmd(esp, ESP_CMD_FLUSH); } else { ESPHME(("no_xtra_byte")); } } ESPHME(("wkarnd_cnt=%d]", (int)count)); esp->hme_fifo_workaround_count = count;}static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count){ esp_cmd(esp, ESP_CMD_FLUSH); while (count) { u8 tmp = *bytes++; sbus_writeb(tmp, esp->eregs + ESP_FDATA); sbus_writeb(0, esp->eregs + ESP_FDATA); count--; }}/* 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 esp *esp, Scsi_Cmnd *scp, int prev_phase, int new_phase){ if (scp->SCp.sent_command != prev_phase) return 0; if (ESP_IRQ_P(esp->dregs)) { /* Yes, we are able to save an interrupt. */ if (esp->erev == fashme) esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); if (esp->erev == fashme) { /* This chip is really losing. */ ESPHME(("HME[")); /* Must latch fifo before reading the interrupt * register else garbage ends up in the FIFO * which confuses the driver utterly. * Happy Meal indeed.... */ ESPHME(("fifo_workaround]")); if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || (esp->sreg2 & ESP_STAT2_F1BYTE)) hme_fifo_read(esp); } 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 esp *esp, 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_IRQ_P(esp->dregs)) { /* Yes, we are able to save an interrupt. */ if (esp->erev == fashme) esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); if (esp->erev == fashme) { /* This chip is really losing. */ ESPHME(("HME[")); /* Must latch fifo before reading the interrupt * register else garbage ends up in the FIFO * which confuses the driver utterly. * Happy Meal indeed.... */ ESPHME(("fifo_workaround]")); if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || (esp->sreg2 & ESP_STAT2_F1BYTE)) hme_fifo_read(esp); } 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;}/* Now some dma helpers. */static void dma_setup(struct esp *esp, __u32 addr, int count, int write){ u32 nreg = sbus_readl(esp->dregs + DMA_CSR); if (write) nreg |= DMA_ST_WRITE; else nreg &= ~(DMA_ST_WRITE); nreg |= DMA_ENABLE; sbus_writel(nreg, esp->dregs + DMA_CSR); if (esp->dma->revision == dvmaesc1) { /* This ESC gate array sucks! */ __u32 src = addr; __u32 dest = src + count; if (dest & (PAGE_SIZE - 1)) count = PAGE_ALIGN(count); sbus_writel(count, esp->dregs + DMA_COUNT); } sbus_writel(addr, esp->dregs + DMA_ADDR);}static void dma_drain(struct esp *esp){ u32 tmp; if (esp->dma->revision == dvmahme) return; if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) { switch (esp->dma->revision) { default: tmp |= DMA_FIFO_STDRAIN; sbus_writel(tmp, esp->dregs + DMA_CSR); case dvmarev3: case dvmaesc1: while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN) udelay(1); }; }}static void dma_invalidate(struct esp *esp){ u32 tmp; if (esp->dma->revision == dvmahme) { sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | (DMA_PARITY_OFF | DMA_2CLKS | DMA_SCSI_DISAB | DMA_INT_ENAB)) & ~(DMA_ST_WRITE | DMA_ENABLE)); sbus_writel(0, esp->dregs + DMA_CSR); sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); /* This is necessary to avoid having the SCSI channel * engine lock up on us. */ sbus_writel(0, esp->dregs + DMA_ADDR); } else { while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ) udelay(1); tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); tmp |= DMA_FIFO_INV; sbus_writel(tmp, esp->dregs + DMA_CSR); tmp &= ~DMA_FIFO_INV; sbus_writel(tmp, esp->dregs + DMA_CSR); }}static inline void dma_flashclear(struct esp *esp){ dma_drain(esp); dma_invalidate(esp);}static int dma_can_transfer(struct esp *esp, Scsi_Cmnd *sp){ __u32 base, end, sz; if (esp->dma->revision == dvmarev3) { sz = sp->SCp.this_residual; if (sz > 0x1000000) sz = 0x1000000; } else { base = ((__u32)((unsigned long)sp->SCp.ptr)); base &= (0x1000000 - 1); end = (base + sp->SCp.this_residual); if (end > 0x1000000) end = 0x1000000; sz = (end - base); } return sz;}/* Misc. esp helper macros. */#define esp_setcount(__eregs, __cnt, __hme) \ sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \ sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \ if (__hme) { \ sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \ sbus_writeb(0, (__eregs) + FAS_RHI); \ }#define esp_getcount(__eregs, __hme) \ ((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \ ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \ ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))#define fcount(__esp) \ (((__esp)->erev == fashme) ? \ (__esp)->hme_fifo_workaround_count : \ sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)#define fnzero(__esp) \ (((__esp)->erev == fashme) ? 0 : \ sbus_readb(((__esp)->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) \ if ((__esp)->erev == esp100) \ esp_cmd((__esp), 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 int esp100_sync_hwbug(struct esp *esp, Scsi_Cmnd *sp, int fifocnt){ /* Do not touch this piece of code. */ if ((!(esp->erev == esp100)) || (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) && !fifocnt) && !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) { if (sp->SCp.phase == in_dataout) esp_cmd(esp, 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, ESP_CMD_SATN); esp_cmd(esp, 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 esp *esp){ u8 tmp; if (esp->erev != esp100) return 0; tmp = sbus_readb(esp->eregs + ESP_INTRPT); if (tmp & ESP_INTR_SR) return 1; return 0;}/* This verifies the BUSID bits during a reselection so
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -