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

📄 scsi_lib.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  scsi_lib.c Copyright (C) 1999 Eric Youngdale * *  SCSI queueing library. *      Initial versions: Eric Youngdale (eric@andante.org). *                        Based upon conversations with large numbers *                        of people at Linux Expo. *//* * The fundamental purpose of this file is to contain a library of utility * routines that can be used by low-level drivers.   Ultimately the idea * is that there should be a sufficiently rich number of functions that it * would be possible for a driver author to fashion a queueing function for * a low-level driver if they wished.   Note however that this file also * contains the "default" versions of these functions, as we don't want to * go through and retrofit queueing functions into all 30 some-odd drivers. */#define __NO_VERSION__#include <linux/module.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/stat.h>#include <linux/blk.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/smp_lock.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/dma.h>#include "scsi.h"#include "hosts.h"#include "constants.h"#include <scsi/scsi_ioctl.h>/* * This entire source file deals with the new queueing code. *//* * Function:    scsi_insert_special_cmd() * * Purpose:     Insert pre-formed command into request queue. * * Arguments:   SCpnt   - command that is ready to be queued. *              at_head - boolean.  True if we should insert at head *                        of queue, false if we should insert at tail. * * Lock status: Assumed that lock is not held upon entry. * * Returns:     Nothing * * Notes:       This function is called from character device and from *              ioctl types of functions where the caller knows exactly *              what SCSI command needs to be issued.   The idea is that *              we merely inject the command into the queue (at the head *              for now), and then call the queue request function to actually *              process it. */int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head){	unsigned long flags;	request_queue_t *q;	ASSERT_LOCK(&io_request_lock, 0);	/*	 * The SCpnt already contains a request structure - we will doctor the	 * thing up with the appropriate values and use that in the actual	 * request queue.	 */	q = &SCpnt->device->request_queue;	SCpnt->request.cmd = SPECIAL;	SCpnt->request.special = (void *) SCpnt;	SCpnt->request.q = NULL;	SCpnt->request.free_list = NULL;	SCpnt->request.nr_segments = 0;	/*	 * We have the option of inserting the head or the tail of the queue.	 * Typically we use the tail for new ioctls and so forth.  We use the	 * head of the queue for things like a QUEUE_FULL message from a	 * device, or a host that is unable to accept a particular command.	 */	spin_lock_irqsave(&io_request_lock, flags);	if (at_head) {		list_add(&SCpnt->request.queue, &q->queue_head);	} else {		/*		 * FIXME(eric) - we always insert at the tail of the		 * list.  Otherwise ioctl commands would always take		 * precedence over normal I/O.  An ioctl on a busy		 * disk might be delayed indefinitely because the		 * request might not float high enough in the queue		 * to be scheduled.		 */		list_add_tail(&SCpnt->request.queue, &q->queue_head);	}	/*	 * Now hit the requeue function for the queue.  If the host is	 * already busy, so be it - we have nothing special to do.  If	 * the host can queue it, then send it off.  	 */	q->request_fn(q);	spin_unlock_irqrestore(&io_request_lock, flags);	return 0;}/* * Function:    scsi_insert_special_req() * * Purpose:     Insert pre-formed request into request queue. * * Arguments:   SRpnt   - request that is ready to be queued. *              at_head - boolean.  True if we should insert at head *                        of queue, false if we should insert at tail. * * Lock status: Assumed that lock is not held upon entry. * * Returns:     Nothing * * Notes:       This function is called from character device and from *              ioctl types of functions where the caller knows exactly *              what SCSI command needs to be issued.   The idea is that *              we merely inject the command into the queue (at the head *              for now), and then call the queue request function to actually *              process it. */int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head){	unsigned long flags;	request_queue_t *q;	ASSERT_LOCK(&io_request_lock, 0);	/*	 * The SCpnt already contains a request structure - we will doctor the	 * thing up with the appropriate values and use that in the actual	 * request queue.	 */	q = &SRpnt->sr_device->request_queue;	SRpnt->sr_request.cmd = SPECIAL;	SRpnt->sr_request.special = (void *) SRpnt;	SRpnt->sr_request.q = NULL;	SRpnt->sr_request.nr_segments = 0;	/*	 * We have the option of inserting the head or the tail of the queue.	 * Typically we use the tail for new ioctls and so forth.  We use the	 * head of the queue for things like a QUEUE_FULL message from a	 * device, or a host that is unable to accept a particular command.	 */	spin_lock_irqsave(&io_request_lock, flags);	if (at_head) {		list_add(&SRpnt->sr_request.queue, &q->queue_head);	} else {		/*		 * FIXME(eric) - we always insert at the tail of the		 * list.  Otherwise ioctl commands would always take		 * precedence over normal I/O.  An ioctl on a busy		 * disk might be delayed indefinitely because the		 * request might not float high enough in the queue		 * to be scheduled.		 */		list_add_tail(&SRpnt->sr_request.queue, &q->queue_head);	}	/*	 * Now hit the requeue function for the queue.  If the host is	 * already busy, so be it - we have nothing special to do.  If	 * the host can queue it, then send it off.  	 */	q->request_fn(q);	spin_unlock_irqrestore(&io_request_lock, flags);	return 0;}/* * Function:    scsi_init_cmd_errh() * * Purpose:     Initialize SCpnt fields related to error handling. * * Arguments:   SCpnt   - command that is ready to be queued. * * Returns:     Nothing * * Notes:       This function has the job of initializing a number of *              fields related to error handling.   Typically this will *              be called once for each command, as required. */int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt){	ASSERT_LOCK(&io_request_lock, 0);	SCpnt->owner = SCSI_OWNER_MIDLEVEL;	SCpnt->reset_chain = NULL;	SCpnt->serial_number = 0;	SCpnt->serial_number_at_timeout = 0;	SCpnt->flags = 0;	SCpnt->retries = 0;	SCpnt->abort_reason = 0;	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);	if (SCpnt->cmd_len == 0)		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);	/*	 * We need saved copies of a number of fields - this is because	 * error handling may need to overwrite these with different values	 * to run different commands, and once error handling is complete,	 * we will need to restore these values prior to running the actual	 * command.	 */	SCpnt->old_use_sg = SCpnt->use_sg;	SCpnt->old_cmd_len = SCpnt->cmd_len;	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;	SCpnt->old_underflow = SCpnt->underflow;	memcpy((void *) SCpnt->data_cmnd,	       (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));	SCpnt->buffer = SCpnt->request_buffer;	SCpnt->bufflen = SCpnt->request_bufflen;	SCpnt->reset_chain = NULL;	SCpnt->internal_timeout = NORMAL_TIMEOUT;	SCpnt->abort_reason = 0;	return 1;}/* * Function:    scsi_queue_next_request() * * Purpose:     Handle post-processing of completed commands. * * Arguments:   SCpnt   - command that may need to be requeued. * * Returns:     Nothing * * Notes:       After command completion, there may be blocks left *              over which weren't finished by the previous command *              this can be for a number of reasons - the main one is *              that a medium error occurred, and the sectors after *              the bad block need to be re-read. * *              If SCpnt is NULL, it means that the previous command *              was completely finished, and we should simply start *              a new command, if possible. * *		This is where a lot of special case code has begun to *		accumulate.  It doesn't really affect readability or *		anything, but it might be considered architecturally *		inelegant.  If more of these special cases start to *		accumulate, I am thinking along the lines of implementing *		an atexit() like technology that gets run when commands *		complete.  I am not convinced that it is worth the *		added overhead, however.  Right now as things stand, *		there are simple conditional checks, and most hosts *		would skip past. * *		Another possible solution would be to tailor different *		handler functions, sort of like what we did in scsi_merge.c. *		This is probably a better solution, but the number of different *		permutations grows as 2**N, and if too many more special cases *		get added, we start to get screwed. */void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt){	int all_clear;	unsigned long flags;	Scsi_Device *SDpnt;	struct Scsi_Host *SHpnt;	ASSERT_LOCK(&io_request_lock, 0);	spin_lock_irqsave(&io_request_lock, flags);	if (SCpnt != NULL) {		/*		 * For some reason, we are not done with this request.		 * This happens for I/O errors in the middle of the request,		 * in which case we need to request the blocks that come after		 * the bad sector.		 */		SCpnt->request.special = (void *) SCpnt;		list_add(&SCpnt->request.queue, &q->queue_head);	}	/*	 * Just hit the requeue function for the queue.	 */	q->request_fn(q);	SDpnt = (Scsi_Device *) q->queuedata;	SHpnt = SDpnt->host;	/*	 * If this is a single-lun device, and we are currently finished	 * with this device, then see if we need to get another device	 * started.  FIXME(eric) - if this function gets too cluttered	 * with special case code, then spin off separate versions and	 * use function pointers to pick the right one.	 */	if (SDpnt->single_lun	    && list_empty(&q->queue_head)	    && SDpnt->device_busy == 0) {		request_queue_t *q;		for (SDpnt = SHpnt->host_queue;		     SDpnt;		     SDpnt = SDpnt->next) {			if (((SHpnt->can_queue > 0)			     && (SHpnt->host_busy >= SHpnt->can_queue))			    || (SHpnt->host_blocked)			    || (SHpnt->host_self_blocked)			    || (SDpnt->device_blocked)) {				break;			}			q = &SDpnt->request_queue;			q->request_fn(q);		}	}	/*	 * Now see whether there are other devices on the bus which	 * might be starved.  If so, hit the request function.  If we	 * don't find any, then it is safe to reset the flag.  If we	 * find any device that it is starved, it isn't safe to reset the	 * flag as the queue function releases the lock and thus some	 * other device might have become starved along the way.	 */	all_clear = 1;	if (SHpnt->some_device_starved) {		for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {			request_queue_t *q;			if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))			    || (SHpnt->host_blocked) 			    || (SHpnt->host_self_blocked)) {				break;			}			if (SDpnt->device_blocked || !SDpnt->starved) {				continue;			}			q = &SDpnt->request_queue;			q->request_fn(q);			all_clear = 0;		}		if (SDpnt == NULL && all_clear) {			SHpnt->some_device_starved = 0;		}	}	spin_unlock_irqrestore(&io_request_lock, flags);}/* * Function:    scsi_end_request() * * Purpose:     Post-processing of completed commands called from interrupt *              handler or a bottom-half handler. * * Arguments:   SCpnt    - command that is complete. *              uptodate - 1 if I/O indicates success, 0 for I/O error. *              sectors  - number of sectors we want to mark. *		requeue  - indicates whether we should requeue leftovers. *		frequeue - indicates that if we release the command block *			   that the queue request function should be called. * * Lock status: Assumed that lock is not held upon entry. * * Returns:     Nothing * * Notes:       This is called for block device requests in order to *              mark some number of sectors as complete. *  *		We are guaranteeing that the request queue will be goosed *		at some point during this call. */static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, 				     int uptodate, 				     int sectors,				     int requeue,				     int frequeue){	struct request *req;

⌨️ 快捷键说明

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