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

📄 scsi_lib.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
			return spnt;		}		/*		 * I am still not entirely satisfied with this solution,		 * but it is good enough for now.  Disks have a number of		 * major numbers associated with them, the primary		 * 8, which we test above, and a secondary range of 7		 * different consecutive major numbers.   If this ever		 * becomes insufficient, then we could add another function		 * to the structure, and generalize this completely.		 */		if( spnt->min_major != 0 		    && spnt->max_major != 0		    && major >= spnt->min_major		    && major <= spnt->max_major )		{			return spnt;		}	}	return NULL;}/* * Function:    scsi_request_fn() * * Purpose:     Generic version of request function for SCSI hosts. * * Arguments:   q       - Pointer to actual queue. * * Returns:     Nothing * * Lock status: IO request lock assumed to be held when called. * * Notes:       The theory is that this function is something which individual *              drivers could also supply if they wished to.   The problem *              is that we have 30 some odd low-level drivers in the kernel *              tree already, and it would be most difficult to retrofit *              this crap into all of them.   Thus this function has the job *              of acting as a generic queue manager for all of those existing *              drivers. */void scsi_request_fn(request_queue_t * q){	struct request *req;	Scsi_Cmnd *SCpnt;	Scsi_Request *SRpnt;	Scsi_Device *SDpnt;	struct Scsi_Host *SHpnt;	struct Scsi_Device_Template *STpnt;	ASSERT_LOCK(&io_request_lock, 1);	SDpnt = (Scsi_Device *) q->queuedata;	if (!SDpnt) {		panic("Missing device");	}	SHpnt = SDpnt->host;	/*	 * To start with, we keep looping until the queue is empty, or until	 * the host is no longer able to accept any more requests.	 */	while (1 == 1) {		/*		 * Check this again - each time we loop through we will have		 * released the lock and grabbed it again, so each time		 * we need to check to see if the queue is plugged or not.		 */		if (SHpnt->in_recovery || q->plugged)			return;		/*		 * If the device cannot accept another request, then quit.		 */		if (SDpnt->device_blocked) {			break;		}		if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))		    || (SHpnt->host_blocked) 		    || (SHpnt->host_self_blocked)) {			/*			 * If we are unable to process any commands at all for			 * this device, then we consider it to be starved.			 * What this means is that there are no outstanding			 * commands for this device and hence we need a			 * little help getting it started again			 * once the host isn't quite so busy.			 */			if (SDpnt->device_busy == 0) {				SDpnt->starved = 1;				SHpnt->some_device_starved = 1;			}			break;		} else {			SDpnt->starved = 0;		} 		/*		 * FIXME(eric)		 * I am not sure where the best place to do this is.  We need		 * to hook in a place where we are likely to come if in user		 * space.   Technically the error handling thread should be		 * doing this crap, but the error handler isn't used by		 * most hosts.		 */		if (SDpnt->was_reset) {			/*			 * We need to relock the door, but we might			 * be in an interrupt handler.  Only do this			 * from user space, since we do not want to			 * sleep from an interrupt.			 *			 * FIXME(eric) - have the error handler thread do			 * this work.			 */			SDpnt->was_reset = 0;			if (SDpnt->removable && !in_interrupt()) {				spin_unlock_irq(&io_request_lock);				scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);				spin_lock_irq(&io_request_lock);				continue;			}		}		/*		 * If we couldn't find a request that could be queued, then we		 * can also quit.		 */		if (list_empty(&q->queue_head))			break;		/*		 * Loop through all of the requests in this queue, and find		 * one that is queueable.		 */		req = blkdev_entry_next_request(&q->queue_head);		/*		 * Find the actual device driver associated with this command.		 * The SPECIAL requests are things like character device or		 * ioctls, which did not originate from ll_rw_blk.  Note that		 * the special field is also used to indicate the SCpnt for		 * the remainder of a partially fulfilled request that can 		 * come up when there is a medium error.  We have to treat		 * these two cases differently.  We differentiate by looking		 * at request.cmd, as this tells us the real story.		 */		if (req->cmd == SPECIAL) {			STpnt = NULL;			SCpnt = (Scsi_Cmnd *) req->special;			SRpnt = (Scsi_Request *) req->special;			if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {				SCpnt = scsi_allocate_device(SRpnt->sr_device, 							     FALSE, FALSE);				if( !SCpnt ) {					break;				}				scsi_init_cmd_from_req(SCpnt, SRpnt);			}		} else {			SRpnt = NULL;			STpnt = scsi_get_request_dev(req);			if (!STpnt) {				panic("Unable to find device associated with request");			}			/*			 * Now try and find a command block that we can use.			 */			if( req->special != NULL ) {				SCpnt = (Scsi_Cmnd *) req->special;				/*				 * We need to recount the number of				 * scatter-gather segments here - the				 * normal case code assumes this to be				 * correct, as it would be a performance				 * lose to always recount.  Handling				 * errors is always unusual, of course.				 */				recount_segments(SCpnt);			} else {				SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE);			}			/*			 * If so, we are ready to do something.  Bump the count			 * while the queue is locked and then break out of the			 * loop. Otherwise loop around and try another request.			 */			if (!SCpnt) {				break;			}		}		/*		 * Now bump the usage count for both the host and the		 * device.		 */		SHpnt->host_busy++;		SDpnt->device_busy++;		/*		 * Finally, before we release the lock, we copy the		 * request to the command block, and remove the		 * request from the request list.   Note that we always		 * operate on the queue head - there is absolutely no		 * reason to search the list, because all of the commands		 * in this queue are for the same device.		 */		blkdev_dequeue_request(req);		if (req != &SCpnt->request && req != &SRpnt->sr_request ) {			memcpy(&SCpnt->request, req, sizeof(struct request));			/*			 * We have copied the data out of the request block -			 * it is now in a field in SCpnt.  Release the request			 * block.			 */			blkdev_release_request(req);		}		/*		 * Now it is finally safe to release the lock.  We are		 * not going to noodle the request list until this		 * request has been queued and we loop back to queue		 * another.  		 */		req = NULL;		spin_unlock_irq(&io_request_lock);		if (SCpnt->request.cmd != SPECIAL) {			/*			 * This will do a couple of things:			 *  1) Fill in the actual SCSI command.			 *  2) Fill in any other upper-level specific fields			 * (timeout).			 *			 * If this returns 0, it means that the request failed			 * (reading past end of disk, reading offline device,			 * etc).   This won't actually talk to the device, but			 * some kinds of consistency checking may cause the				 * request to be rejected immediately.			 */			if (STpnt == NULL) {				STpnt = scsi_get_request_dev(req);			}			/* 			 * This sets up the scatter-gather table (allocating if			 * required).  Hosts that need bounce buffers will also			 * get those allocated here.  			 */			if (!SDpnt->scsi_init_io_fn(SCpnt)) {				SCpnt = __scsi_end_request(SCpnt, 0, 							   SCpnt->request.nr_sectors, 0, 0);				if( SCpnt != NULL )				{					panic("Should not have leftover blocks\n");				}				spin_lock_irq(&io_request_lock);				SHpnt->host_busy--;				SDpnt->device_busy--;				continue;			}			/*			 * Initialize the actual SCSI command for this request.			 */			if (!STpnt->init_command(SCpnt)) {				scsi_release_buffers(SCpnt);				SCpnt = __scsi_end_request(SCpnt, 0, 							   SCpnt->request.nr_sectors, 0, 0);				if( SCpnt != NULL )				{					panic("Should not have leftover blocks\n");				}				spin_lock_irq(&io_request_lock);				SHpnt->host_busy--;				SDpnt->device_busy--;				continue;			}		}		/*		 * Finally, initialize any error handling parameters, and set up		 * the timers for timeouts.		 */		scsi_init_cmd_errh(SCpnt);		/*		 * Dispatch the command to the low-level driver.		 */		scsi_dispatch_cmd(SCpnt);		/*		 * Now we need to grab the lock again.  We are about to mess		 * with the request queue and try to find another command.		 */		spin_lock_irq(&io_request_lock);	}}/* * Function:    scsi_block_requests() * * Purpose:     Utility function used by low-level drivers to prevent further *		commands from being queued to the device. * * Arguments:   SHpnt       - Host in question * * Returns:     Nothing * * Lock status: No locks are assumed held. * * Notes:       There is no timer nor any other means by which the requests *		get unblocked other than the low-level driver calling *		scsi_unblock_requests(). */void scsi_block_requests(struct Scsi_Host * SHpnt){	SHpnt->host_self_blocked = TRUE;}/* * Function:    scsi_unblock_requests() * * Purpose:     Utility function used by low-level drivers to allow further *		commands from being queued to the device. * * Arguments:   SHpnt       - Host in question * * Returns:     Nothing * * Lock status: No locks are assumed held. * * Notes:       There is no timer nor any other means by which the requests *		get unblocked other than the low-level driver calling *		scsi_unblock_requests(). * *		This is done as an API function so that changes to the *		internals of the scsi mid-layer won't require wholesale *		changes to drivers that use this feature. */void scsi_unblock_requests(struct Scsi_Host * SHpnt){	Scsi_Device *SDloop;	SHpnt->host_self_blocked = FALSE;	/* Now that we are unblocked, try to start the queues. */	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next)		scsi_queue_next_request(&SDloop->request_queue, NULL);}/* * Function:    scsi_report_bus_reset() * * Purpose:     Utility function used by low-level drivers to report that *		they have observed a bus reset on the bus being handled. * * Arguments:   SHpnt       - Host in question *		channel     - channel on which reset was observed. * * Returns:     Nothing * * Lock status: No locks are assumed held. * * Notes:       This only needs to be called if the reset is one which *		originates from an unknown location.  Resets originated *		by the mid-level itself don't need to call this, but there *		should be no harm. * *		The main purpose of this is to make sure that a CHECK_CONDITION *		is properly treated. */void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel){	Scsi_Device *SDloop;	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {		if (channel == SDloop->channel) {			SDloop->was_reset = 1;			SDloop->expecting_cc_ua = 1;		}	}}/* * FIXME(eric) - these are empty stubs for the moment.  I need to re-implement * host blocking from scratch. The theory is that hosts that wish to block * will register/deregister using these functions instead of the old way * of setting the wish_block flag. * * The details of the implementation remain to be settled, however the * stubs are here now so that the actual drivers will properly compile. */void scsi_register_blocked_host(struct Scsi_Host * SHpnt){}void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt){}

⌨️ 快捷键说明

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