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 + -
显示快捷键?