⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atari_scsi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			   */			if (atari_dma_residual & 0x1ff) {				DMA_PRINTK("SCSI DMA: DMA bug corrected, "					   "difference %ld bytes\n",					   512 - (atari_dma_residual & 0x1ff));				atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff;			}		}		tt_scsi_dma.dma_ctrl = 0;	}	/* If the DMA is finished, fetch the rest bytes and turn it off */	if (dma_stat & 0x40) {		atari_dma_residual = 0;		if ((dma_stat & 1) == 0)			atari_scsi_fetch_restbytes();		tt_scsi_dma.dma_ctrl = 0;	}#endif /* REAL_DMA */		NCR5380_intr (0, 0, 0);#if 0	/* To be sure the int is not masked */	atari_enable_irq( IRQ_TT_MFP_SCSI );#endif}static void scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp){#ifdef REAL_DMA	int dma_stat;	/* Turn off DMA and select sector counter register before	 * accessing the status register (Atari recommendation!)	 */	st_dma.dma_mode_status = 0x90;	dma_stat = st_dma.dma_mode_status;	/* Bit 0 indicates some error in the DMA process... don't know	 * what happened exactly (no further docu).	 */	if (!(dma_stat & 0x01)) {		/* DMA error */		printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR());	}	/* If the DMA was active, but now bit 1 is not clear, it is some	 * other 5380 interrupt that finishes the DMA transfer. We have to	 * calculate the number of residual bytes and give a warning if	 * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)	 */	if (atari_dma_active && (dma_stat & 0x02)) {		unsigned long	transferred;		transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;		/* The ST-DMA address is incremented in 2-byte steps, but the		 * data are written only in 16-byte chunks. If the number of		 * transferred bytes is not divisible by 16, the remainder is		 * lost somewhere in outer space.		 */		if (transferred & 15)			printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "			       "ST-DMA fifo\n", transferred & 15);		atari_dma_residual = HOSTDATA_DMALEN - transferred;		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",			   atari_dma_residual);	}	else		atari_dma_residual = 0;	atari_dma_active = 0;	if (atari_dma_orig_addr) {		/* If the dribble buffer was used on a read operation, copy the DMA-ed		 * data to the original destination address.		 */		memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),		       HOSTDATA_DMALEN - atari_dma_residual);		atari_dma_orig_addr = NULL;	}#endif /* REAL_DMA */	NCR5380_intr (0, 0, 0);}#ifdef REAL_DMAstatic void atari_scsi_fetch_restbytes( void ){	int nr;	char *src, *dst;	unsigned long phys_dst;	/* fetch rest bytes in the DMA register */	phys_dst = SCSI_DMA_READ_P(dma_addr);	nr = phys_dst & 3;	if (nr) {		/* there are 'nr' bytes left for the last long address		   before the DMA pointer */		phys_dst ^= nr;		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",			   nr, phys_dst);		/* The content of the DMA pointer is a physical address!  */		dst = phys_to_virt(phys_dst);		DMA_PRINTK(" = virt addr %p\n", dst);		for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr)			*dst++ = *src++;	}}#endif /* REAL_DMA */static int falcon_got_lock = 0;static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);static int falcon_trying_lock = 0;static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);static int falcon_dont_release = 0;/* This function releases the lock on the DMA chip if there is no * connected command and the disconnected queue is empty. On * releasing, instances of falcon_get_lock are awoken, that put * themselves to sleep for fairness. They can now try to get the lock * again (but others waiting longer more probably will win). */static voidfalcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ){	unsigned long	oldflags;			if (IS_A_TT()) return;		save_flags(oldflags);	cli();	if (falcon_got_lock &&		!hostdata->disconnected_queue &&		!hostdata->issue_queue &&		!hostdata->connected) {		if (falcon_dont_release) {#if 0			printk("WARNING: Lock release not allowed. Ignored\n");#endif			restore_flags(oldflags);			return;		}		falcon_got_lock = 0;		stdma_release();		wake_up( &falcon_fairness_wait );	}	restore_flags(oldflags);}/* This function manages the locking of the ST-DMA. * If the DMA isn't locked already for SCSI, it tries to lock it by * calling stdma_lock(). But if the DMA is locked by the SCSI code and * there are other drivers waiting for the chip, we do not issue the * command immediately but wait on 'falcon_fairness_queue'. We will be * waked up when the DMA is unlocked by some SCSI interrupt. After that * we try to get the lock again. * But we must be prepared that more than one instance of * falcon_get_lock() is waiting on the fairness queue. They should not * try all at once to call stdma_lock(), one is enough! For that, the * first one sets 'falcon_trying_lock', others that see that variable * set wait on the queue 'falcon_try_wait'. * Complicated, complicated.... Sigh... */static void falcon_get_lock( void ){	unsigned long	oldflags;	if (IS_A_TT()) return;	save_flags(oldflags);	cli();	while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )		sleep_on( &falcon_fairness_wait );	while (!falcon_got_lock) {		if (in_interrupt())			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );		if (!falcon_trying_lock) {			falcon_trying_lock = 1;			stdma_lock(scsi_falcon_intr, NULL);			falcon_got_lock = 1;			falcon_trying_lock = 0;			wake_up( &falcon_try_wait );		}		else {			sleep_on( &falcon_try_wait );		}	}		restore_flags(oldflags);	if (!falcon_got_lock)		panic("Falcon SCSI: someone stole the lock :-(\n");}/* This is the wrapper function for NCR5380_queue_command(). It just * tries to get the lock on the ST-DMA (see above) and then calls the * original function. */#if 0int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)){	/* falcon_get_lock();	 * ++guenther: moved to NCR5380_queue_command() to prevent	 * race condition, see there for an explanation.	 */	return( NCR5380_queue_command( cmd, done ) );}#endifint atari_scsi_detect (Scsi_Host_Template *host){	static int called = 0;	struct Scsi_Host *instance;	if (!MACH_IS_ATARI ||	    (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||	    called)		return( 0 );	host->proc_name = "Atari";	atari_scsi_reg_read  = IS_A_TT() ? atari_scsi_tt_reg_read :					   atari_scsi_falcon_reg_read;	atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :					   atari_scsi_falcon_reg_write;	/* setup variables */	host->can_queue =		(setup_can_queue > 0) ? setup_can_queue :		IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE;	host->cmd_per_lun =		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun :		IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN;	/* Force sg_tablesize to 0 on a Falcon! */	host->sg_tablesize =		!IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE :		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE;	if (setup_hostid >= 0)		host->this_id = setup_hostid;	else {		/* use 7 as default */		host->this_id = 7;		/* Test if a host id is set in the NVRam */		if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {			unsigned char b = nvram_read_byte( 14 );			/* Arbitration enabled? (for TOS) If yes, use configured host ID */			if (b & 0x80)				host->this_id = b & 7;		}	}#ifdef SUPPORT_TAGS	if (setup_use_tagged_queuing < 0)		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;#endif#ifdef REAL_DMA	/* If running on a Falcon and if there's TT-Ram (i.e., more than one	 * memory block, since there's always ST-Ram in a Falcon), then allocate a	 * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative	 * Ram.	 */	if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&	    !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {		atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");		if (!atari_dma_buffer) {			printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "					"double buffer\n" );			return( 0 );		}		atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );		atari_dma_orig_addr = 0;	}#endif	instance = scsi_register (host, sizeof (struct NCR5380_hostdata));	if(instance == NULL)	{		atari_stram_free(atari_dma_buffer);		atari_dma_buffer = 0;		return 0;	}	atari_scsi_host = instance;       /* Set irq to 0, to avoid that the mid-level code disables our interrupt        * during queue_command calls. This is completely unnecessary, and even        * worse causes bad problems on the Falcon, where the int is shared with        * IDE and floppy! */       instance->irq = 0;#ifdef CONFIG_ATARI_SCSI_RESET_BOOT	atari_scsi_reset_boot();#endif	NCR5380_init (instance, 0);	if (IS_A_TT()) {		/* This int is actually "pseudo-slow", i.e. it acts like a slow		 * interrupt after having cleared the pending flag for the DMA		 * interrupt. */		request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,		            "SCSI NCR5380", scsi_tt_intr);		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */#ifdef REAL_DMA		tt_scsi_dma.dma_ctrl = 0;		atari_dma_residual = 0;#endif /* REAL_DMA */#ifdef REAL_DMA#ifdef CONFIG_TT_DMA_EMUL		if (MACH_IS_HADES) {			request_irq(IRQ_AUTO_2, hades_dma_emulator,				    IRQ_TYPE_PRIO, "Hades DMA emulator",				    hades_dma_emulator);		}#endif		if (MACH_IS_MEDUSA || MACH_IS_HADES) {			/* While the read overruns (described by Drew Eckhardt in			 * NCR5380.c) never happened on TTs, they do in fact on the Medusa			 * (This was the cause why SCSI didn't work right for so long			 * there.) Since handling the overruns slows down a bit, I turned			 * the #ifdef's into a runtime condition.			 *			 * In principle it should be sufficient to do max. 1 byte with			 * PIO, but there is another problem on the Medusa with the DMA			 * rest data register. So 'atari_read_overruns' is currently set			 * to 4 to avoid having transfers that aren't a multiple of 4. If			 * the rest data bug is fixed, this can be lowered to 1.			 */			atari_read_overruns = 4;		}#endif			}	else { /* ! IS_A_TT */				/* Nothing to do for the interrupt: the ST-DMA is initialized		 * already by atari_init_INTS()		 */#ifdef REAL_DMA		atari_dma_residual = 0;		atari_dma_active = 0;		atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000					: 0xff000000);#endif	}	printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "#ifdef SUPPORT_TAGS			"TAGGED-QUEUING=%s "#endif			"HOSTID=%d",			instance->host_no, instance->hostt->can_queue,			instance->hostt->cmd_per_lun,			instance->hostt->sg_tablesize,#ifdef SUPPORT_TAGS			setup_use_tagged_queuing ? "yes" : "no",#endif			instance->hostt->this_id );	NCR5380_print_options (instance);	printk ("\n");	called = 1;	return( 1 );}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -