📄 53c700.c
字号:
NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, MSG_ARRAY_SIZE); /* I'm just being paranoid here, the command should * already have been flushed from the cache */ NCR_700_dma_cache_wback((unsigned long)slot->cmnd->cmnd, slot->cmnd->cmd_len); } } else if(dsps == A_RESELECTED_DURING_SELECTION) { /* This section is full of debugging code because I've * never managed to reach it. I think what happens is * that, because the 700 runs with selection * interrupts enabled the whole time that we take a * selection interrupt before we manage to get to the * reselected script interrupt */ __u8 reselection_id = NCR_700_readb(host, SFBR_REG); struct NCR_700_command_slot *slot; /* Take out our own ID */ reselection_id &= ~(1<<host->this_id); /* I've never seen this happen, so keep this as a printk rather * than a debug */ printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n", host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count); { /* FIXME: DEBUGGING CODE */ __u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]); int i; for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) { if(SG >= to32bit(&hostdata->slots[i].pSG[0]) && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS])) break; } printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset); SCp = hostdata->slots[i].cmnd; } if(SCp != NULL) { slot = (struct NCR_700_command_slot *)SCp->host_scribble; /* change slot from busy to queued to redo command */ slot->state = NCR_700_SLOT_QUEUED; } hostdata->cmd = NULL; if(reselection_id == 0) { if(hostdata->reselection_id == 0xff) { printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no); return 0; } else { printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n", host->host_no); reselection_id = hostdata->reselection_id; } } else { /* convert to real ID */ reselection_id = bitmap_to_number(reselection_id); } hostdata->reselection_id = reselection_id; /* just in case we have a stale simple tag message, clear it */ hostdata->msgin[1] = 0; NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); if(hostdata->tag_negotiated & (1<<reselection_id)) { resume_offset = hostdata->pScript + Ent_GetReselectionWithTag; } else { resume_offset = hostdata->pScript + Ent_GetReselectionData; } } else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) { /* we've just disconnected from the bus, do nothing since * a return here will re-run the queued command slot * that may have been interrupted by the initial selection */ DEBUG((" SELECTION COMPLETED\n")); } else if((dsps & 0xfffff0f0) == A_MSG_IN) { resume_offset = process_message(host, hostdata, SCp, dsp, dsps); } else if((dsps & 0xfffff000) == 0) { __u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8; printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n", host->host_no, pun, lun, NCR_700_condition[i], NCR_700_phase[j], dsp - hostdata->pScript); if(SCp != NULL) { print_command(SCp->cmnd); if(SCp->use_sg) { for(i = 0; i < SCp->use_sg + 1; i++) { printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr); } } } NCR_700_internal_bus_reset(host); } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) { printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n", host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript); resume_offset = dsp; } else { printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n", host->host_no, pun, lun, dsps, dsp - hostdata->pScript); NCR_700_internal_bus_reset(host); } return resume_offset;}/* We run the 53c700 with selection interrupts always enabled. This * means that the chip may be selected as soon as the bus frees. On a * busy bus, this can be before the scripts engine finishes its * processing. Therefore, part of the selection processing has to be * to find out what the scripts engine is doing and complete the * function if necessary (i.e. process the pending disconnect or save * the interrupted initial selection */STATIC inline __u32process_selection(struct Scsi_Host *host, __u32 dsp){ __u8 id = 0; /* Squash compiler warning */ int count = 0; __u32 resume_offset = 0; struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; Scsi_Cmnd *SCp = hostdata->cmd; __u8 sbcl; for(count = 0; count < 5; count++) { id = NCR_700_readb(host, hostdata->chip710 ? CTEST9_REG : SFBR_REG); /* Take out our own ID */ id &= ~(1<<host->this_id); if(id != 0) break; udelay(5); } sbcl = NCR_700_readb(host, SBCL_REG); if((sbcl & SBCL_IO) == 0) { /* mark as having been selected rather than reselected */ id = 0xff; } else { /* convert to real ID */ hostdata->reselection_id = id = bitmap_to_number(id); DEBUG(("scsi%d: Reselected by %d\n", host->host_no, id)); } if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset)); switch(dsp - hostdata->pScript) { case Ent_Disconnect1: case Ent_Disconnect2: save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript); break; case Ent_Disconnect3: case Ent_Disconnect4: save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript); break; case Ent_Disconnect5: case Ent_Disconnect6: save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript); break; case Ent_Disconnect7: case Ent_Disconnect8: save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript); break; case Ent_Finish1: case Ent_Finish2: process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata); break; default: slot->state = NCR_700_SLOT_QUEUED; break; } } hostdata->state = NCR_700_HOST_BUSY; hostdata->cmd = NULL; /* clear any stale simple tag message */ hostdata->msgin[1] = 0; NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); if(id == 0xff) { /* Selected as target, Ignore */ resume_offset = hostdata->pScript + Ent_SelectedAsTarget; } else if(hostdata->tag_negotiated & (1<<id)) { resume_offset = hostdata->pScript + Ent_GetReselectionWithTag; } else { resume_offset = hostdata->pScript + Ent_GetReselectionData; } return resume_offset;}static inline voidNCR_700_clear_fifo(struct Scsi_Host *host) { const struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; if(hostdata->chip710) { NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG); } else { NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); }}static inline voidNCR_700_flush_fifo(struct Scsi_Host *host) { const struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; if(hostdata->chip710) { NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG); udelay(10); NCR_700_writeb(0, host, CTEST8_REG); } else { NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG); udelay(10); NCR_700_writeb(0, host, DFIFO_REG); }}STATIC intNCR_700_start_command(Scsi_Cmnd *SCp){ struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0]; unsigned long flags; __u16 count = 1; /* for IDENTIFY message */ save_flags(flags); cli(); if(hostdata->state != NCR_700_HOST_FREE) { /* keep this inside the lock to close the race window where * the running command finishes on another CPU while we don't * change the state to queued on this one */ slot->state = NCR_700_SLOT_QUEUED; restore_flags(flags); DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n", SCp->host->host_no, slot->cmnd, slot)); return 0; } hostdata->state = NCR_700_HOST_BUSY; hostdata->cmd = SCp; slot->state = NCR_700_SLOT_BUSY; /* keep interrupts disabled until we have the command correctly * set up so we cannot take a selection interrupt */ hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE, SCp->lun); /* for INQUIRY or REQUEST_SENSE commands, we cannot be sure * if the negotiated transfer parameters still hold, so * always renegotiate them */ if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE) { NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); } /* REQUEST_SENSE is asking for contingent I_T_L(_Q) status. * If a contingent allegiance condition exists, the device * will refuse all tags, so send the request sense as untagged * */ if((hostdata->tag_negotiated & (1<<SCp->target)) && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) { hostdata->msgout[count++] = A_SIMPLE_TAG_MSG; hostdata->msgout[count++] = slot->tag; } if(hostdata->fast && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) { memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg, sizeof(NCR_700_SDTR_msg)); count += sizeof(NCR_700_SDTR_msg); NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } script_patch_16(hostdata->script, MessageCount, count); script_patch_ID(hostdata->script, Device_ID, 1<<SCp->target); script_patch_32_abs(hostdata->script, CommandAddress, slot->pCmd); script_patch_16(hostdata->script, CommandCount, SCp->cmd_len); /* finally plumb the beginning of the SG list into the script * */ script_patch_32_abs(hostdata->script, SGScriptStartAddress, to32bit(&slot->pSG[0].ins)); NCR_700_clear_fifo(SCp->host); if(slot->resume_offset == 0) slot->resume_offset = hostdata->pScript; /* now perform all the writebacks and invalidates */ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, count); NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); NCR_700_dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len); NCR_700_dma_cache_inv((unsigned long)hostdata->status, 1); /* set the synchronous period/offset */ NCR_700_writeb(NCR_700_get_SXFER(SCp->device), SCp->host, SXFER_REG); NCR_700_writel(slot->temp, SCp->host, TEMP_REG); NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG); /* allow interrupts here so that if we're selected we can take * a selection interrupt. The script start may not be * effective in this case, but the selection interrupt will * save our command in that case */ restore_flags(flags); return 1;}voidNCR_700_intr(int irq, void *dev_id, struct pt_regs *regs){ struct Scsi_Host *host = (struct Scsi_Host *)dev_id; struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; __u8 istat; __u32 resume_offset = 0; __u8 pun = 0xff, lun = 0xff; unsigned long flags; /* Unfortunately, we have to take the io_request_lock here * rather than the host lock hostdata->lock because we're * looking to exclude queuecommand from messing with the * registers while we're processing the interrupt. Since * queuecommand is called holding io_request_lock, and we have * to take io_request_lock before we call the command * scsi_done, we would get a deadlock if we took * hostdata->lock here and in queuecommand (because the order * of locking in queuecommand: 1) io_request_lock then 2) * hostdata->lock would be the reverse of taking it in this * routine */ spin_lock_irqsave(&io_request_lock, flags); if((istat = NCR_700_readb(host, ISTAT_REG)) & (SCSI_INT_PENDING | DMA_INT_PENDING)) { __u32 dsps; __u8 sstat0 = 0, dstat = 0; __u32 dsp; Scsi_Cmnd *SCp = hostdata->cmd; enum NCR_700_Host_State state; state = hostdata->state; SCp = hostdata->cmd; if(istat & SCSI_INT_PENDING) { udelay(10); sstat0 = NCR_700_readb(host, SSTAT0_REG); } if(istat & DMA_INT_PENDING) { udelay(10); dstat = NCR_700_readb(host, DSTAT_REG); } dsps = NCR_700_readl(host, DSPS_REG); dsp = NCR_700_readl(host, DSP_REG); DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n", host->host_no, istat, sstat0, dstat, (dsp - (__u32)(hostdata->pScript))/4, dsp, dsps)); if(SCp != NULL) { pun = SCp->target; lun = SCp->lun; } if(sstat0 & SCSI_RESET_DETECTED) { Scsi_Device *SDp; int i; hostdata->state = NCR_700_HOST_BUSY; printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); /* clear all the negotiated parameters */ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) SDp->hostdata = 0; /* clear all the slots and their pending commands */ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { Scsi_Cmnd *SCp; struct NCR_700_command_slot *slot = &hostdata->slots[i]; if(slot->state == NCR_700_SLOT_FREE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -