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 + -
显示快捷键?