📄 53c700.c
字号:
count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) - (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f; } else { count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; } if(hostdata->fast) synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; /* get the data direction */ ddir = NCR_700_readb(host, CTEST0_REG) & 0x01; if (ddir) { /* Receive */ if (synchronous) count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4; else if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL) ++count; } else { /* Send */ __u8 sstat = NCR_700_readb(host, SSTAT1_REG); if (sstat & SODL_REG_FULL) ++count; if (synchronous && (sstat & SODR_REG_FULL)) ++count; }#ifdef NCR_700_DEBUG if(count) printk("RESIDUAL IS %d (ddir %d)\n", count, ddir);#endif return count;}/* print out the SCSI wires and corresponding phase from the SBCL register * in the chip */static inline char *sbcl_to_string(__u8 sbcl){ int i; static char ret[256]; ret[0]='\0'; for(i=0; i<8; i++) { if((1<<i) & sbcl) strcat(ret, NCR_700_SBCL_bits[i]); } strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]); return ret;}static inline __u8bitmap_to_number(__u8 bitmap){ __u8 i; for(i=0; i<8 && !(bitmap &(1<<i)); i++) ; return i;}/* Pull a slot off the free list */STATIC struct NCR_700_command_slot *find_empty_slot(struct NCR_700_Host_Parameters *hostdata){ struct NCR_700_command_slot *slot = hostdata->free_list; if(slot == NULL) { /* sanity check */ if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST) printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST); return NULL; } if(slot->state != NCR_700_SLOT_FREE) /* should panic! */ printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n"); hostdata->free_list = slot->ITL_forw; slot->ITL_forw = NULL; /* NOTE: set the state to busy here, not queued, since this * indicates the slot is in use and cannot be run by the IRQ * finish routine. If we cannot queue the command when it * is properly build, we then change to NCR_700_SLOT_QUEUED */ slot->state = NCR_700_SLOT_BUSY; hostdata->command_slot_count++; return slot;}STATIC void free_slot(struct NCR_700_command_slot *slot, struct NCR_700_Host_Parameters *hostdata){ int hash; struct NCR_700_command_slot **forw, **back; if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) { printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); } if(slot->state == NCR_700_SLOT_FREE) { printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot); } /* remove from queues */ if(slot->tag != NCR_700_NO_TAG) { hash = hash_ITLQ(slot->cmnd->target, slot->cmnd->lun, slot->tag); if(slot->ITLQ_forw == NULL) back = &hostdata->ITLQ_Hash_back[hash]; else back = &slot->ITLQ_forw->ITLQ_back; if(slot->ITLQ_back == NULL) forw = &hostdata->ITLQ_Hash_forw[hash]; else forw = &slot->ITLQ_back->ITLQ_forw; *forw = slot->ITLQ_forw; *back = slot->ITLQ_back; } hash = hash_ITL(slot->cmnd->target, slot->cmnd->lun); if(slot->ITL_forw == NULL) back = &hostdata->ITL_Hash_back[hash]; else back = &slot->ITL_forw->ITL_back; if(slot->ITL_back == NULL) forw = &hostdata->ITL_Hash_forw[hash]; else forw = &slot->ITL_back->ITL_forw; *forw = slot->ITL_forw; *back = slot->ITL_back; slot->resume_offset = 0; slot->cmnd = NULL; slot->state = NCR_700_SLOT_FREE; slot->ITL_forw = hostdata->free_list; hostdata->free_list = slot; hostdata->command_slot_count--;}/* This routine really does very little. The command is indexed on the ITL and (if tagged) the ITLQ lists in _queuecommand */STATIC voidsave_for_reselection(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, __u32 dsp){ /* Its just possible that this gets executed twice */ if(SCp != NULL) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; slot->resume_offset = dsp; } hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL;}/* Most likely nexus is the oldest in each case */STATIC inline struct NCR_700_command_slot *find_ITL_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun){ int hash = hash_ITL(pun, lun); struct NCR_700_command_slot *slot = hostdata->ITL_Hash_back[hash]; while(slot != NULL && !(slot->cmnd->target == pun && slot->cmnd->lun == lun)) slot = slot->ITL_back; return slot;}STATIC inline struct NCR_700_command_slot *find_ITLQ_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun, __u8 tag){ int hash = hash_ITLQ(pun, lun, tag); struct NCR_700_command_slot *slot = hostdata->ITLQ_Hash_back[hash]; while(slot != NULL && !(slot->cmnd->target == pun && slot->cmnd->lun == lun && slot->tag == tag)) slot = slot->ITLQ_back;#ifdef NCR_700_TAG_DEBUG if(slot != NULL) { struct NCR_700_command_slot *n = slot->ITLQ_back; while(n != NULL && n->cmnd->target != pun && n->cmnd->lun != lun && n->tag != tag) n = n->ITLQ_back; if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun && n->tag == tag) { printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n", tag); } }#endif return slot;}/* This translates the SDTR message offset and period to a value * which can be loaded into the SXFER_REG. * * NOTE: According to SCSI-2, the true transfer period (in ns) is * actually four times this period value */STATIC inline __u8NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, __u8 offset, __u8 period){ int XFERP; __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); __u8 max_offset = (hostdata->chip710 ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); /* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum * period. It is set in NCR_700_chip_setup() */ if(period < NCR_700_SDTR_msg[3]) { printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); period = NCR_700_SDTR_msg[3]; } XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; if(offset > max_offset) { printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", offset, max_offset); offset = max_offset; } if(XFERP < min_xferp) { printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", XFERP, min_xferp); XFERP = min_xferp; } return (offset & 0x0f) | (XFERP & 0x07)<<4;}STATIC inline voidNCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, struct NCR_700_command_slot *slot){ if(SCp->sc_data_direction != SCSI_DATA_NONE && SCp->sc_data_direction != SCSI_DATA_UNKNOWN) { int pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction); if(SCp->use_sg) { pci_unmap_sg(hostdata->pci_dev, SCp->buffer, SCp->use_sg, pci_direction); } else { pci_unmap_single(hostdata->pci_dev, slot->dma_handle, SCp->request_bufflen, pci_direction); } }}STATIC inline voidNCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, int result){ hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; if(SCp != NULL) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; NCR_700_unmap(hostdata, SCp, slot); pci_unmap_single(hostdata->pci_dev, slot->pCmd, sizeof(SCp->cmnd), PCI_DMA_TODEVICE); if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {#ifdef NCR_700_DEBUG printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", SCp, SCp->cmnd[7], result); print_sense("53c700", SCp);#endif SCp->use_sg = SCp->cmnd[8]; if(result == 0) result = SCp->cmnd[7]; } free_slot(slot, hostdata); SCp->host_scribble = NULL; SCp->result = result; SCp->scsi_done(SCp); if(NCR_700_get_depth(SCp->device) == 0 || NCR_700_get_depth(SCp->device) > NCR_700_MAX_TAGS) printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n", NCR_700_get_depth(SCp->device)); NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1); } else { printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n"); }}STATIC voidNCR_700_internal_bus_reset(struct Scsi_Host *host){ /* Bus reset */ NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG); udelay(50); NCR_700_writeb(0, host, SCNTL1_REG);}STATIC voidNCR_700_chip_setup(struct Scsi_Host *host){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; __u32 dcntl_extra = 0; __u8 min_period; __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); if(hostdata->chip710) { __u8 burst_disable = hostdata->burst_disable ? BURST_DISABLE : 0; dcntl_extra = COMPAT_700_MODE; NCR_700_writeb(dcntl_extra, host, DCNTL_REG); NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, host, DMODE_710_REG); NCR_700_writeb(burst_disable | (hostdata->differential ? DIFF : 0), host, CTEST7_REG); NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG); NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY | AUTO_ATN, host, SCNTL0_REG); } else { NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, host, DMODE_700_REG); NCR_700_writeb(hostdata->differential ? DIFF : 0, host, CTEST7_REG); if(hostdata->fast) { /* this is for 700-66, does nothing on 700 */ NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION | GENERATE_RECEIVE_PARITY, host, CTEST8_REG); } else { NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY | AUTO_ATN, host, SCNTL0_REG); } } NCR_700_writeb(1 << host->this_id, host, SCID_REG); NCR_700_writeb(0, host, SBCL_REG); NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG); NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG); NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG); NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG); if(hostdata->clock > 75) { printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock); /* do the best we can, but the async clock will be out * of spec: sync divider 2, async divider 3 */ DEBUG(("53c700: sync 2 async 3\n")); NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG); NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock/2; } else if(hostdata->clock > 50 && hostdata->clock <= 75) { /* sync divider 1.5, async divider 3 */ DEBUG(("53c700: sync 1.5 async 3\n")); NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG); NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock*2; hostdata->sync_clock /= 3; } else if(hostdata->clock > 37 && hostdata->clock <= 50) { /* sync divider 1, async divider 2 */ DEBUG(("53c700: sync 1 async 2\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock; } else if(hostdata->clock > 25 && hostdata->clock <=37) { /* sync divider 1, async divider 1.5 */ DEBUG(("53c700: sync 1 async 1.5\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock; } else { DEBUG(("53c700: sync 1 async 1\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG); /* sync divider 1, async divider 1 */ hostdata->sync_clock = hostdata->clock; } /* Calculate the actual minimum period that can be supported * by our synchronous clock speed. See the 710 manual for * exact details of this calculation which is based on a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -