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

📄 atari_ncr5380.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  * NCR 5380 generic driver routines.  These should make it *trivial* * 	to implement 5380 SCSI drivers under Linux with a non-trantor *	architecture. * *	Note that these routines also work with NR53c400 family chips. * * Copyright 1993, Drew Eckhardt *	Visionary Computing  *	(Unix and Linux consulting and custom programming) * 	drew@colorado.edu *	+1 (303) 666-5836 * * DISTRIBUTION RELEASE 6.  * * For more information, please consult  * * NCR 5380 Family * SCSI Protocol Controller * Databook * * NCR Microelectronics * 1635 Aeroplaza Drive * Colorado Springs, CO 80916 * 1+ (719) 578-3400 * 1+ (800) 334-5454 *//* * ++roman: To port the 5380 driver to the Atari, I had to do some changes in * this file, too: * *  - Some of the debug statements were incorrect (undefined variables and the *    like). I fixed that. * *  - In information_transfer(), I think a #ifdef was wrong. Looking at the *    possible DMA transfer size should also happen for REAL_DMA. I added this *    in the #if statement. * *  - When using real DMA, information_transfer() should return in a DATAOUT *    phase after starting the DMA. It has nothing more to do. * *  - The interrupt service routine should run main after end of DMA, too (not *    only after RESELECTION interrupts). Additionally, it should _not_ test *    for more interrupts after running main, since a DMA process may have *    been started and interrupts are turned on now. The new int could happen *    inside the execution of NCR5380_intr(), leading to recursive *    calls. * *  - I've added a function merge_contiguous_buffers() that tries to *    merge scatter-gather buffers that are located at contiguous *    physical addresses and can be processed with the same DMA setup. *    Since most scatter-gather operations work on a page (4K) of *    4 buffers (1K), in more than 90% of all cases three interrupts and *    DMA setup actions are saved. * * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA *    and USLEEP, because these were messing up readability and will never be *    needed for Atari SCSI. *  * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' *   stuff), and 'main' is executed in a bottom half if awoken by an *   interrupt. * * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..." *   constructs. In my eyes, this made the source rather unreadable, so I *   finally replaced that by the *_PRINTK() macros. * *//* * Further development / testing that should be done :  * 1.  Test linked command handling code after Eric is ready with  *     the high level code. */#if (NDEBUG & NDEBUG_LISTS)#define LIST(x,y) \  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \    if ((x)==(y)) udelay(5); }#define REMOVE(w,x,y,z) \  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \    if ((x)==(y)) udelay(5); }#else#define LIST(x,y)#define REMOVE(w,x,y,z)#endif#ifndef notyet#undef LINKED#endif/* * Design * Issues : * * The other Linux SCSI drivers were written when Linux was Intel PC-only, * and specifically for each board rather than each chip.  This makes their * adaptation to platforms like the Mac (Some of which use NCR5380's) * more difficult than it has to be. * * Also, many of the SCSI drivers were written before the command queuing * routines were implemented, meaning their implementations of queued  * commands were hacked on rather than designed in from the start. * * When I designed the Linux SCSI drivers I figured that  * while having two different SCSI boards in a system might be useful * for debugging things, two of the same type wouldn't be used. * Well, I was wrong and a number of users have mailed me about running * multiple high-performance SCSI boards in a server. * * Finally, when I get questions from users, I have no idea what  * revision of my driver they are running. * * This driver attempts to address these problems : * This is a generic 5380 driver.  To use it on a different platform,  * one simply writes appropriate system specific macros (ie, data * transfer - some PC's will use the I/O bus, 68K's must use  * memory mapped) and drops this file in their 'C' wrapper. * * As far as command queueing, two queues are maintained for  * each 5380 in the system - commands that haven't been issued yet, * and commands that are currently executing.  This means that an  * unlimited number of commands may be queued, letting  * more commands propagate from the higher driver levels giving higher  * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported,  * allowing multiple commands to propagate all the way to a SCSI-II device  * while a command is already executing. * * To solve the multiple-boards-in-the-same-system problem,  * there is a separate instance structure for each instance * of a 5380 in the system.  So, multiple NCR5380 drivers will * be able to coexist with appropriate changes to the high level * SCSI code.   * * A NCR5380_PUBLIC_REVISION macro is provided, with the release * number (updated for each public release) printed by the  * NCR5380_print_options command, which should be called from the  * wrapper detect function, so that I know what release of the driver * users are using. * * Issues specific to the NCR5380 :  * * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead  * piece of hardware that requires you to sit in a loop polling for  * the REQ signal as long as you are connected.  Some devices are  * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect  * while doing long seek operations. *  * The workaround for this is to keep track of devices that have * disconnected.  If the device hasn't disconnected, for commands that * should disconnect, we do something like  * * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } *  * Some tweaking of N and M needs to be done.  An algorithm based  * on "time to data" would give the best results as long as short time * to datas (ie, on the same track) were considered, however these  * broken devices are the exception rather than the rule and I'd rather * spend my time optimizing for the normal case. * * Architecture : * * At the heart of the design is a coroutine, NCR5380_main, * which is started when not running by the interrupt handler, * timer, and queue command function.  It attempts to establish * I_T_L or I_T_L_Q nexuses by removing the commands from the  * issue queue and calling NCR5380_select() if a nexus  * is not established.  * * Once a nexus is established, the NCR5380_information_transfer() * phase goes through the various phases as instructed by the target. * if the target goes into MSG IN and sends a DISCONNECT message, * the command structure is placed into the per instance disconnected * queue, and NCR5380_main tries to find more work.  If USLEEP * was defined, and the target is idle for too long, the system * will try to sleep. * * If a command has disconnected, eventually an interrupt will trigger, * calling NCR5380_intr()  which will in turn call NCR5380_reselect * to reestablish a nexus.  This will run main if necessary. * * On command termination, the done function will be called as  * appropriate. * * SCSI pointers are maintained in the SCp field of SCSI command  * structures, being initialized after the command is connected * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. * Note that in violation of the standard, an implicit SAVE POINTERS operation * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. *//* * Using this file : * This file a skeleton Linux SCSI driver for the NCR 5380 series * of chips.  To use it, you write an architecture specific functions  * and macros and include this file in your driver. * * These macros control options :  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically *	for commands that return with a CHECK CONDITION status.  * * LINKED - if defined, linked commands are supported. * * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. * * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible * * These macros MUST be defined : *  * NCR5380_read(register)  - read from the specified register * * NCR5380_write(register, value) - write to the specific register  * * Either real DMA *or* pseudo DMA may be implemented * REAL functions :  * NCR5380_REAL_DMA should be defined if real DMA is to be used. * Note that the DMA setup functions should return the number of bytes  *	that they were able to program the controller for. * * Also note that generic i386/PC versions of these macros are  *	available as NCR5380_i386_dma_write_setup, *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. * * NCR5380_dma_write_setup(instance, src, count) - initialize * NCR5380_dma_read_setup(instance, dst, count) - initialize * NCR5380_dma_residual(instance); - residual count * * PSEUDO functions : * NCR5380_pwrite(instance, src, count) * NCR5380_pread(instance, dst, count); * * If nothing specific to this implementation needs doing (ie, with external * hardware), you must also define  *   * NCR5380_queue_command * NCR5380_reset * NCR5380_abort * NCR5380_proc_info * * to be the global entry points into the specific driver, ie  * #define NCR5380_queue_command t128_queue_command. * * If this is not done, the routines will be defined as static functions * with the NCR5380* names and the user must provide a globally * accessible wrapper function. * * The generic driver is initialized by calling NCR5380_init(instance), * after setting the appropriate host specific fields and ID.  If the  * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, * possible) function may be used.  Before the specific driver initialization * code finishes, NCR5380_print_options should be called. */static struct Scsi_Host *first_instance = NULL;static Scsi_Host_Template *the_template = NULL;/* Macros ease life... :-) */#define	SETUP_HOSTDATA(in)				\    struct NCR5380_hostdata *hostdata =			\	(struct NCR5380_hostdata *)(in)->hostdata#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))#define	HOSTNO		instance->host_no#define	H_NO(cmd)	(cmd)->host->host_no#ifdef SUPPORT_TAGS/* * Functions for handling tagged queuing * ===================================== * * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes: * * Using consecutive numbers for the tags is no good idea in my eyes. There * could be wrong re-usings if the counter (8 bit!) wraps and some early * command has been preempted for a long time. My solution: a bitfield for * remembering used tags. * * There's also the problem that each target has a certain queue size, but we * cannot know it in advance :-( We just see a QUEUE_FULL status being * returned. So, in this case, the driver internal queue size assumption is * reduced to the number of active tags if QUEUE_FULL is returned by the * target. The command is returned to the mid-level, but with status changed * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL * correctly. * * We're also not allowed running tagged commands as long as an untagged * command is active. And REQUEST SENSE commands after a contingent allegiance * condition _must_ be untagged. To keep track whether an untagged command has * been issued, the host->busy array is still employed, as it is without * support for tagged queuing. * * One could suspect that there are possible race conditions between * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(), * which already guaranteed to be running at most once. It is also the only * place where tags/LUNs are allocated. So no other allocation can slip * between that pair, there could only happen a reselection, which can free a * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes * important: the tag bit must be cleared before 'nr_allocated' is decreased. *//* -1 for TAG_NONE is not possible with unsigned char cmd->tag */#undef TAG_NONE#define TAG_NONE 0xff/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */#if (MAX_TAGS % 32) != 0#error "MAX_TAGS must be a multiple of 32!"#endiftypedef struct {    char	allocated[MAX_TAGS/8];    int		nr_allocated;    int		queue_size;} TAG_ALLOC;static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */static void __init init_tags( void ){    int target, lun;    TAG_ALLOC *ta;        if (!setup_use_tagged_queuing)	return;        for( target = 0; target < 8; ++target ) {	for( lun = 0; lun < 8; ++lun ) {	    ta = &TagAlloc[target][lun];	    memset( &ta->allocated, 0, MAX_TAGS/8 );	    ta->nr_allocated = 0;	    /* At the beginning, assume the maximum queue size we could	     * support (MAX_TAGS). This value will be decreased if the target	     * returns QUEUE_FULL status.	     */	    ta->queue_size = MAX_TAGS;	}    }}/* Check if we can issue a command to this LUN: First see if the LUN is marked * busy by an untagged command. If the command should use tagged queuing, also * check that there is a free tag and the target's queue won't overflow. This * function should be called with interrupts disabled to avoid race * conditions. */ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ){    SETUP_HOSTDATA(cmd->host);    if (hostdata->busy[cmd->target] & (1 << cmd->lun))	return( 1 );    if (!should_be_tagged ||	!setup_use_tagged_queuing || !cmd->device->tagged_supported)	return( 0 );    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=	TagAlloc[cmd->target][cmd->lun].queue_size ) {	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",		    H_NO(cmd), cmd->target, cmd->lun );	return( 1 );    }    return( 0 );}/* Allocate a tag for a command (there are no checks anymore, check_lun_busy() * must be called before!), or reserve the LUN in 'busy' if the command is * untagged. */static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ){    SETUP_HOSTDATA(cmd->host);    /* If we or the target don't support tagged queuing, allocate the LUN for     * an untagged command.     */    if (!should_be_tagged ||	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {	cmd->tag = TAG_NONE;	hostdata->busy[cmd->target] |= (1 << cmd->lun);	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "		    "command\n", H_NO(cmd), cmd->target, cmd->lun );    }    else {	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );	set_bit( cmd->tag, &ta->allocated );	ta->nr_allocated++;	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "		    "(now %d tags in use)\n",		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,		    ta->nr_allocated );    }}/* Mark the tag of command 'cmd' as free, or in case of an untagged command, * unlock the LUN. */static void cmd_free_tag( Scsi_Cmnd *cmd ){    SETUP_HOSTDATA(cmd->host);    if (cmd->tag == TAG_NONE) {	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",		    H_NO(cmd), cmd->target, cmd->lun );

⌨️ 快捷键说明

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