atari_ncr5380.c

来自「linux 内核源代码」· C语言 代码 · 共 2,131 行 · 第 1/5 页

C
2,131
字号
/* * 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. */#include <scsi/scsi_dbg.h>#include <scsi/scsi_transport_spi.h>#if (NDEBUG & NDEBUG_LISTS)#define LIST(x, y)						\	do {							\		printk("LINE:%d   Adding %p to %p\n",		\		       __LINE__, (void*)(x), (void*)(y));	\		if ((x) == (y))					\			udelay(5);				\	} while (0)#define REMOVE(w, x, y, z)					\	do {							\		printk("LINE:%d   Removing: %p->%p  %p->%p \n",	\		       __LINE__, (void*)(w), (void*)(x),	\		       (void*)(y), (void*)(z));			\		if ((x) == (y))					\			udelay(5);				\	} while (0)#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 struct 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	SET_NEXT(cmd,next)	((cmd)->host_scribble = (void *)(next))#define	NEXTADDR(cmd)		((Scsi_Cmnd **)&(cmd)->host_scribble)#define	HOSTNO		instance->host_no#define	H_NO(cmd)	(cmd)->device->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 0xfftypedef struct {	DECLARE_BITMAP(allocated, MAX_TAGS);	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];			bitmap_zero(ta->allocated, MAX_TAGS);			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->device->host);	if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))		return 1;	if (!should_be_tagged ||	    !setup_use_tagged_queuing || !cmd->device->tagged_supported)		return 0;	if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=	    TagAlloc[cmd->device->id][cmd->device->lun].queue_size) {		TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n",			   H_NO(cmd), cmd->device->id, cmd->device->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->device->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->device->id] |= (1 << cmd->device->lun);		TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged "			   "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun);	} else {		TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->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->device->id,			   cmd->device->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->device->host);	if (cmd->tag == TAG_NONE) {		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);		TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n",			   H_NO(cmd), cmd->device->id, cmd->device->lun);	} else if (cmd->tag >= MAX_TAGS) {		printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",		       H_NO(cmd), cmd->tag);

⌨️ 快捷键说明

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