scsi.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,249 行 · 第 1/3 页

C
1,249
字号
		}	}}void scsi_log_completion(struct scsi_cmnd *cmd, int disposition){	unsigned int level;	struct scsi_device *sdev;	/*	 * If ML COMPLETE log level is greater than or equal to:	 *	 * 1: log disposition, result, opcode + command, and conditionally	 * sense data for failures or non SUCCESS dispositions.	 *	 * 2: same as 1 but for all command completions.	 *	 * 3: same as 2 plus dump cmd address	 *	 * 4: same as 3 plus dump extra junk	 */	if (unlikely(scsi_logging_level)) {		level = SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT,				       SCSI_LOG_MLCOMPLETE_BITS);		if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||		    (level > 1)) {			sdev = cmd->device;			printk(KERN_INFO "scsi <%d:%d:%d:%d> done ",			       sdev->host->host_no, sdev->channel, sdev->id,			       sdev->lun);			if (level > 2)				printk("0x%p ", cmd);			/*			 * Dump truncated values, so we usually fit within			 * 80 chars.			 */			switch (disposition) {			case SUCCESS:				printk("SUCCESS");				break;			case NEEDS_RETRY:				printk("RETRY  ");				break;			case ADD_TO_MLQUEUE:				printk("MLQUEUE");				break;			case FAILED:				printk("FAILED ");				break;			case TIMEOUT_ERROR:				/* 				 * If called via scsi_times_out.				 */				printk("TIMEOUT");				break;			default:				printk("UNKNOWN");			}			printk(" %8x ", cmd->result);			scsi_print_command(cmd);			if (status_byte(cmd->result) & CHECK_CONDITION) {				/*				 * XXX The print_sense formatting/prefix				 * doesn't match this function.				 */				scsi_print_sense("", cmd);			}			if (level > 3) {				printk(KERN_INFO "scsi host busy %d failed %d\n",				       sdev->host->host_busy,				       sdev->host->host_failed);			}		}	}}#endif/* * Function:    scsi_dispatch_command * * Purpose:     Dispatch a command to the low-level driver. * * Arguments:   cmd - command block we are dispatching. * * Notes: */int scsi_dispatch_cmd(struct scsi_cmnd *cmd){	struct Scsi_Host *host = cmd->device->host;	unsigned long flags = 0;	unsigned long timeout;	int rtn = 0;	/* check if the device is still usable */	if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {		/* in SDEV_DEL we error all commands. DID_NO_CONNECT		 * returns an immediate error upwards, and signals		 * that the device is no longer present */		cmd->result = DID_NO_CONNECT << 16;		scsi_done(cmd);		/* return 0 (because the command has been processed) */		goto out;	}	/* Assign a unique nonzero serial_number. */	/* XXX(hch): this is racy */	if (++serial_number == 0)		serial_number = 1;	cmd->serial_number = serial_number;	cmd->pid = scsi_pid++;	/* 	 * If SCSI-2 or lower, store the LUN value in cmnd.	 */	if (cmd->device->scsi_level <= SCSI_2) {		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |			       (cmd->device->lun << 5 & 0xe0);	}	/*	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so	 * we can avoid the drive not being ready.	 */	timeout = host->last_reset + MIN_RESET_DELAY;	if (host->resetting && time_before(jiffies, timeout)) {		int ticks_remaining = timeout - jiffies;		/*		 * NOTE: This may be executed from within an interrupt		 * handler!  This is bad, but for now, it'll do.  The irq		 * level of the interrupt handler has been masked out by the		 * platform dependent interrupt handling code already, so the		 * sti() here will not cause another call to the SCSI host's		 * interrupt handler (assuming there is one irq-level per		 * host).		 */		while (--ticks_remaining >= 0)			mdelay(1 + 999 / HZ);		host->resetting = 0;	}	scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);	scsi_log_send(cmd);	/*	 * We will use a queued command if possible, otherwise we will	 * emulate the queuing and calling of completion function ourselves.	 */	cmd->state = SCSI_STATE_QUEUED;	cmd->owner = SCSI_OWNER_LOWLEVEL;	/*	 * Before we queue this command, check if the command	 * length exceeds what the host adapter can handle.	 */	if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {		SCSI_LOG_MLQUEUE(3,				printk("queuecommand : command too long.\n"));		cmd->result = (DID_ABORT << 16);		spin_lock_irqsave(host->host_lock, flags);		scsi_done(cmd);		spin_unlock_irqrestore(host->host_lock, flags);		goto out;	}	spin_lock_irqsave(host->host_lock, flags);	if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {		cmd->result = (DID_NO_CONNECT << 16);		scsi_done(cmd);	} else {		rtn = host->hostt->queuecommand(cmd, scsi_done);	}	spin_unlock_irqrestore(host->host_lock, flags);	if (rtn) {		scsi_queue_insert(cmd,				(rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?				 rtn : SCSI_MLQUEUE_HOST_BUSY);		SCSI_LOG_MLQUEUE(3,		    printk("queuecommand : request rejected\n"));	} out:	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));	return rtn;}/* * Function:    scsi_init_cmd_from_req * * Purpose:     Queue a SCSI command * Purpose:     Initialize a struct scsi_cmnd from a struct scsi_request * * Arguments:   cmd       - command descriptor. *              sreq      - Request from the queue. * * Lock status: None needed. * * Returns:     Nothing. * * Notes:       Mainly transfer data from the request structure to the *              command structure.  The request structure is allocated *              using the normal memory allocator, and requests can pile *              up to more or less any depth.  The command structure represents *              a consumable resource, as these are allocated into a pool *              when the SCSI subsystem initializes.  The preallocation is *              required so that in low-memory situations a disk I/O request *              won't cause the memory manager to try and write out a page. *              The request structure is generally used by ioctls and character *              devices. */void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq){	sreq->sr_command = cmd;	cmd->owner = SCSI_OWNER_MIDLEVEL;	cmd->cmd_len = sreq->sr_cmd_len;	cmd->use_sg = sreq->sr_use_sg;	cmd->request = sreq->sr_request;	memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd));	cmd->serial_number = 0;	cmd->serial_number_at_timeout = 0;	cmd->bufflen = sreq->sr_bufflen;	cmd->buffer = sreq->sr_buffer;	cmd->retries = 0;	cmd->allowed = sreq->sr_allowed;	cmd->done = sreq->sr_done;	cmd->timeout_per_command = sreq->sr_timeout_per_command;	cmd->sc_data_direction = sreq->sr_data_direction;	cmd->sglist_len = sreq->sr_sglist_len;	cmd->underflow = sreq->sr_underflow;	cmd->sc_request = sreq;	memcpy(cmd->cmnd, sreq->sr_cmnd, sizeof(sreq->sr_cmnd));	/*	 * Zero the sense buffer.  Some host adapters automatically request	 * sense on error.  0 is not a valid sense code.	 */	memset(cmd->sense_buffer, 0, sizeof(sreq->sr_sense_buffer));	cmd->request_buffer = sreq->sr_buffer;	cmd->request_bufflen = sreq->sr_bufflen;	cmd->old_use_sg = cmd->use_sg;	if (cmd->cmd_len == 0)		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);	cmd->old_cmd_len = cmd->cmd_len;	cmd->sc_old_data_direction = cmd->sc_data_direction;	cmd->old_underflow = cmd->underflow;	/*	 * Start the timer ticking.	 */	cmd->internal_timeout = NORMAL_TIMEOUT;	cmd->abort_reason = 0;	cmd->result = 0;	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_init_cmd_from_req()\n"));}/* * Per-CPU I/O completion queue. */static DEFINE_PER_CPU(struct list_head, scsi_done_q);/** * scsi_done - Enqueue the finished SCSI command into the done queue. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * * This function is the mid-level's (SCSI Core) interrupt routine, which * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues * the command to the done queue for further processing. * * This is the producer of the done queue who enqueues at the tail. * * This function is interrupt context safe. */void scsi_done(struct scsi_cmnd *cmd){	/*	 * We don't have to worry about this one timing out any more.	 * If we are unable to remove the timer, then the command	 * has already timed out.  In which case, we have no choice but to	 * let the timeout function run, as we have no idea where in fact	 * that function could really be.  It might be on another processor,	 * etc, etc.	 */	if (!scsi_delete_timer(cmd))		return;	__scsi_done(cmd);}/* Private entry to scsi_done() to complete a command when the timer * isn't running --- used by scsi_times_out */void __scsi_done(struct scsi_cmnd *cmd){	unsigned long flags;	/*	 * Set the serial numbers back to zero	 */	cmd->serial_number = 0;	cmd->serial_number_at_timeout = 0;	cmd->state = SCSI_STATE_BHQUEUE;	cmd->owner = SCSI_OWNER_BH_HANDLER;	/*	 * Next, enqueue the command into the done queue.	 * It is a per-CPU queue, so we just disable local interrupts	 * and need no spinlock.	 */	local_irq_save(flags);	list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));	raise_softirq_irqoff(SCSI_SOFTIRQ);	local_irq_restore(flags);}/** * scsi_softirq - Perform post-interrupt processing of finished SCSI commands. * * This is the consumer of the done queue. * * This is called with all interrupts enabled.  This should reduce * interrupt latency, stack depth, and reentrancy of the low-level * drivers. */static void scsi_softirq(struct softirq_action *h){	int disposition;	LIST_HEAD(local_q);	local_irq_disable();	list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);	local_irq_enable();	while (!list_empty(&local_q)) {		struct scsi_cmnd *cmd = list_entry(local_q.next,						   struct scsi_cmnd, eh_entry);		list_del_init(&cmd->eh_entry);		disposition = scsi_decide_disposition(cmd);		scsi_log_completion(cmd, disposition);		switch (disposition) {		case SUCCESS:			scsi_finish_command(cmd);			break;		case NEEDS_RETRY:			scsi_retry_command(cmd);			break;		case ADD_TO_MLQUEUE:			scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);			break;		default:			if (!scsi_eh_scmd_add(cmd, 0))				scsi_finish_command(cmd);		}	}}/* * Function:    scsi_retry_command * * Purpose:     Send a command back to the low level to be retried. * * Notes:       This command is always executed in the context of the *              bottom half handler, or the error handler thread. Low *              level drivers should not become re-entrant as a result of *              this. */int scsi_retry_command(struct scsi_cmnd *cmd){	/*	 * Restore the SCSI command state.	 */	scsi_setup_cmd_retry(cmd);        /*         * Zero the sense information from the last time we tried         * this command.         */	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));	return scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);}/* * Function:    scsi_finish_command * * Purpose:     Pass command off to upper layer for finishing of I/O *              request, waking processes that are waiting on results, *              etc. */void scsi_finish_command(struct scsi_cmnd *cmd){	struct scsi_device *sdev = cmd->device;	struct Scsi_Host *shost = sdev->host;	struct scsi_request *sreq;	scsi_device_unbusy(sdev);        /*         * Clear the flags which say that the device/host is no longer         * capable of accepting new commands.  These are set in scsi_queue.c         * for both the queue full condition on a device, and for a         * host full condition on the host.	 *	 * XXX(hch): What about locking?         */        shost->host_blocked = 0;        sdev->device_blocked = 0;	/*	 * If we have valid sense information, then some kind of recovery	 * must have taken place.  Make a note of this.	 */	if (SCSI_SENSE_VALID(cmd))

⌨️ 快捷键说明

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