53c700.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,957 行 · 第 1/5 页
C
1,957 行
hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f; else hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f; hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0); if(banner == 0) { printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n"); banner = 1; } printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no, hostdata->chip710 ? "53c710" : (hostdata->fast ? "53c700-66" : "53c700"), hostdata->rev, hostdata->differential ? "(Differential)" : ""); /* reset the chip */ NCR_700_chip_reset(host); return host;}intNCR_700_release(struct Scsi_Host *host){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, hostdata->script, hostdata->pScript); return 1;}static inline __u8NCR_700_identify(int can_disconnect, __u8 lun){ return IDENTIFY_BASE | ((can_disconnect) ? 0x40 : 0) | (lun & NCR_700_LUN_MASK);}/* * Function : static int data_residual (Scsi_Host *host) * * Purpose : return residual data count of what's in the chip. If you * really want to know what this function is doing, it's almost a * direct transcription of the algorithm described in the 53c710 * guide, except that the DBC and DFIFO registers are only 6 bits * wide on a 53c700. * * Inputs : host - SCSI host */static inline intNCR_700_data_residual (struct Scsi_Host *host) { struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; int count, synchronous = 0; unsigned int ddir; if(hostdata->chip710) { 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){ 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); } 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, struct 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;}STATIC inline voidNCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, struct NCR_700_command_slot *slot){ if(SCp->sc_data_direction != DMA_NONE && SCp->sc_data_direction != DMA_BIDIRECTIONAL) { if(SCp->use_sg) { dma_unmap_sg(hostdata->dev, SCp->buffer, SCp->use_sg, SCp->sc_data_direction); } else { dma_unmap_single(hostdata->dev, slot->dma_handle, SCp->request_bufflen, SCp->sc_data_direction); } }}STATIC inline voidNCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, struct 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); dma_unmap_single(hostdata->dev, slot->pCmd, sizeof(SCp->cmnd), DMA_TO_DEVICE); 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); scsi_print_sense("53c700", SCp);#endif /* restore the old result if the request sense was * successful */ if(result == 0) result = SCp->cmnd[7]; /* now restore the original command */ memcpy((void *) SCp->cmnd, (void *) SCp->data_cmnd, sizeof(SCp->data_cmnd)); SCp->request_buffer = SCp->buffer; SCp->request_bufflen = SCp->bufflen; SCp->use_sg = SCp->old_use_sg; SCp->cmd_len = SCp->old_cmd_len; SCp->sc_data_direction = SCp->sc_old_data_direction; SCp->underflow = SCp->old_underflow; } free_slot(slot, hostdata);#ifdef NCR_700_DEBUG if(NCR_700_get_depth(SCp->device) == 0 || NCR_700_get_depth(SCp->device) > SCp->device->queue_depth) printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n", NCR_700_get_depth(SCp->device));#endif /* NCR_700_DEBUG */ NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1); SCp->host_scribble = NULL; SCp->result = result; SCp->scsi_done(SCp); } 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 * setting of the SXFER register */ min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); hostdata->min_period = NCR_700_MIN_PERIOD; if(min_period > NCR_700_MIN_PERIOD) hostdata->min_period = min_period;}STATIC voidNCR_700_chip_reset(struct Scsi_Host *host){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; if(hostdata->chip710) { NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG); udelay(100); NCR_700_writeb(0, host, ISTAT_REG); } else { NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); udelay(100); NCR_700_writeb(0, host, DCNTL_REG); } mdelay(1000); NCR_700_chip_setup(host);}/* The heart of the message processing engine is that the instruction * immediately after the INT is the normal case (and so must be CLEAR * ACK). If we want to do something else, we call that routine in * scripts and set temp to be the normal case + 8 (skipping the CLEAR * ACK) so that the routine returns correctly to resume its activity * */STATIC __u32process_extended_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?