1 |
1275 |
phoenix |
/*
|
2 |
|
|
* scsi_queue.c Copyright (C) 1997 Eric Youngdale
|
3 |
|
|
*
|
4 |
|
|
* generic mid-level SCSI queueing.
|
5 |
|
|
*
|
6 |
|
|
* The point of this is that we need to track when hosts are unable to
|
7 |
|
|
* accept a command because they are busy. In addition, we track devices
|
8 |
|
|
* that cannot accept a command because of a QUEUE_FULL condition. In both
|
9 |
|
|
* of these cases, we enter the command in the queue. At some later point,
|
10 |
|
|
* we attempt to remove commands from the queue and retry them.
|
11 |
|
|
*/
|
12 |
|
|
|
13 |
|
|
#define __NO_VERSION__
|
14 |
|
|
#include <linux/module.h>
|
15 |
|
|
|
16 |
|
|
#include <linux/sched.h>
|
17 |
|
|
#include <linux/timer.h>
|
18 |
|
|
#include <linux/string.h>
|
19 |
|
|
#include <linux/slab.h>
|
20 |
|
|
#include <linux/ioport.h>
|
21 |
|
|
#include <linux/kernel.h>
|
22 |
|
|
#include <linux/stat.h>
|
23 |
|
|
#include <linux/blk.h>
|
24 |
|
|
#include <linux/interrupt.h>
|
25 |
|
|
#include <linux/delay.h>
|
26 |
|
|
#include <linux/smp_lock.h>
|
27 |
|
|
|
28 |
|
|
#define __KERNEL_SYSCALLS__
|
29 |
|
|
|
30 |
|
|
#include <linux/unistd.h>
|
31 |
|
|
|
32 |
|
|
#include <asm/system.h>
|
33 |
|
|
#include <asm/irq.h>
|
34 |
|
|
#include <asm/dma.h>
|
35 |
|
|
|
36 |
|
|
#include "scsi.h"
|
37 |
|
|
#include "hosts.h"
|
38 |
|
|
#include "constants.h"
|
39 |
|
|
|
40 |
|
|
/*
|
41 |
|
|
* TODO:
|
42 |
|
|
* 1) Prevent multiple traversals of list to look for commands to
|
43 |
|
|
* queue.
|
44 |
|
|
* 2) Protect against multiple insertions of list at the same time.
|
45 |
|
|
* DONE:
|
46 |
|
|
* 1) Set state of scsi command to a new state value for ml queue.
|
47 |
|
|
* 2) Insert into queue when host rejects command.
|
48 |
|
|
* 3) Make sure status code is properly passed from low-level queue func
|
49 |
|
|
* so that internal_cmnd properly returns the right value.
|
50 |
|
|
* 4) Insert into queue when QUEUE_FULL.
|
51 |
|
|
* 5) Cull queue in bottom half handler.
|
52 |
|
|
* 6) Check usage count prior to queue insertion. Requeue if usage
|
53 |
|
|
* count is 0.
|
54 |
|
|
* 7) Don't send down any more commands if the host/device is busy.
|
55 |
|
|
*/
|
56 |
|
|
|
57 |
|
|
static const char RCSid[] = "$Header: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/linux/linux-2.4/drivers/scsi/scsi_queue.c,v 1.1.1.1 2004-04-15 02:08:35 phoenix Exp $";
|
58 |
|
|
|
59 |
|
|
|
60 |
|
|
/*
|
61 |
|
|
* Function: scsi_mlqueue_insert()
|
62 |
|
|
*
|
63 |
|
|
* Purpose: Insert a command in the midlevel queue.
|
64 |
|
|
*
|
65 |
|
|
* Arguments: cmd - command that we are adding to queue.
|
66 |
|
|
* reason - why we are inserting command to queue.
|
67 |
|
|
*
|
68 |
|
|
* Lock status: Assumed that lock is not held upon entry.
|
69 |
|
|
*
|
70 |
|
|
* Returns: Nothing.
|
71 |
|
|
*
|
72 |
|
|
* Notes: We do this for one of two cases. Either the host is busy
|
73 |
|
|
* and it cannot accept any more commands for the time being,
|
74 |
|
|
* or the device returned QUEUE_FULL and can accept no more
|
75 |
|
|
* commands.
|
76 |
|
|
* Notes: This could be called either from an interrupt context or a
|
77 |
|
|
* normal process context.
|
78 |
|
|
*/
|
79 |
|
|
int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
|
80 |
|
|
{
|
81 |
|
|
struct Scsi_Host *host;
|
82 |
|
|
unsigned long flags;
|
83 |
|
|
|
84 |
|
|
SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd));
|
85 |
|
|
|
86 |
|
|
/*
|
87 |
|
|
* We are inserting the command into the ml queue. First, we
|
88 |
|
|
* cancel the timer, so it doesn't time out.
|
89 |
|
|
*/
|
90 |
|
|
scsi_delete_timer(cmd);
|
91 |
|
|
|
92 |
|
|
host = cmd->host;
|
93 |
|
|
|
94 |
|
|
/*
|
95 |
|
|
* Next, set the appropriate busy bit for the device/host.
|
96 |
|
|
*/
|
97 |
|
|
if (reason == SCSI_MLQUEUE_HOST_BUSY) {
|
98 |
|
|
/*
|
99 |
|
|
* Protect against race conditions. If the host isn't busy,
|
100 |
|
|
* assume that something actually completed, and that we should
|
101 |
|
|
* be able to queue a command now. Note that there is an implicit
|
102 |
|
|
* assumption that every host can always queue at least one command.
|
103 |
|
|
* If a host is inactive and cannot queue any commands, I don't see
|
104 |
|
|
* how things could possibly work anyways.
|
105 |
|
|
*/
|
106 |
|
|
if (host->host_busy == 0) {
|
107 |
|
|
if (scsi_retry_command(cmd) == 0) {
|
108 |
|
|
return 0;
|
109 |
|
|
}
|
110 |
|
|
}
|
111 |
|
|
host->host_blocked = TRUE;
|
112 |
|
|
} else {
|
113 |
|
|
/*
|
114 |
|
|
* Protect against race conditions. If the device isn't busy,
|
115 |
|
|
* assume that something actually completed, and that we should
|
116 |
|
|
* be able to queue a command now. Note that there is an implicit
|
117 |
|
|
* assumption that every host can always queue at least one command.
|
118 |
|
|
* If a host is inactive and cannot queue any commands, I don't see
|
119 |
|
|
* how things could possibly work anyways.
|
120 |
|
|
*/
|
121 |
|
|
if (cmd->device->device_busy == 0) {
|
122 |
|
|
if (scsi_retry_command(cmd) == 0) {
|
123 |
|
|
return 0;
|
124 |
|
|
}
|
125 |
|
|
}
|
126 |
|
|
cmd->device->device_blocked = TRUE;
|
127 |
|
|
}
|
128 |
|
|
|
129 |
|
|
/*
|
130 |
|
|
* Register the fact that we own the thing for now.
|
131 |
|
|
*/
|
132 |
|
|
cmd->state = SCSI_STATE_MLQUEUE;
|
133 |
|
|
cmd->owner = SCSI_OWNER_MIDLEVEL;
|
134 |
|
|
cmd->bh_next = NULL;
|
135 |
|
|
|
136 |
|
|
/*
|
137 |
|
|
* Decrement the counters, since these commands are no longer
|
138 |
|
|
* active on the host/device.
|
139 |
|
|
*/
|
140 |
|
|
spin_lock_irqsave(&io_request_lock, flags);
|
141 |
|
|
cmd->host->host_busy--;
|
142 |
|
|
cmd->device->device_busy--;
|
143 |
|
|
spin_unlock_irqrestore(&io_request_lock, flags);
|
144 |
|
|
|
145 |
|
|
/*
|
146 |
|
|
* Insert this command at the head of the queue for it's device.
|
147 |
|
|
* It will go before all other commands that are already in the queue.
|
148 |
|
|
*/
|
149 |
|
|
scsi_insert_special_cmd(cmd, 1);
|
150 |
|
|
return 0;
|
151 |
|
|
}
|