OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acorn/] [scsi/] [queue.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/drivers/acorn/scsi/queue.c: queue handling primitives
3
 *
4
 *  Copyright (C) 1997-2000 Russell King
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation.
9
 *
10
 *  Changelog:
11
 *   15-Sep-1997 RMK    Created.
12
 *   11-Oct-1997 RMK    Corrected problem with queue_remove_exclude
13
 *                      not updating internal linked list properly
14
 *                      (was causing commands to go missing).
15
 *   30-Aug-2000 RMK    Use Linux list handling and spinlocks
16
 */
17
#include <linux/module.h>
18
#include <linux/blk.h>
19
#include <linux/kernel.h>
20
#include <linux/string.h>
21
#include <linux/slab.h>
22
#include <linux/spinlock.h>
23
#include <linux/list.h>
24
#include <linux/init.h>
25
 
26
#include "../../scsi/scsi.h"
27
 
28
#define DEBUG
29
 
30
typedef struct queue_entry {
31
        struct list_head   list;
32
        Scsi_Cmnd          *SCpnt;
33
#ifdef DEBUG
34
        unsigned long      magic;
35
#endif
36
} QE_t;
37
 
38
#ifdef DEBUG
39
#define QUEUE_MAGIC_FREE        0xf7e1c9a3
40
#define QUEUE_MAGIC_USED        0xf7e1cc33
41
 
42
#define SET_MAGIC(q,m)  ((q)->magic = (m))
43
#define BAD_MAGIC(q,m)  ((q)->magic != (m))
44
#else
45
#define SET_MAGIC(q,m)  do { } while (0)
46
#define BAD_MAGIC(q,m)  (0)
47
#endif
48
 
49
#include "queue.h"
50
 
51
#define NR_QE   32
52
 
53
/*
54
 * Function: void queue_initialise (Queue_t *queue)
55
 * Purpose : initialise a queue
56
 * Params  : queue - queue to initialise
57
 */
58
int queue_initialise (Queue_t *queue)
59
{
60
        unsigned int nqueues = NR_QE;
61
        QE_t *q;
62
 
63
        spin_lock_init(&queue->queue_lock);
64
        INIT_LIST_HEAD(&queue->head);
65
        INIT_LIST_HEAD(&queue->free);
66
 
67
        /*
68
         * If life was easier, then SCpnt would have a
69
         * host-available list head, and we wouldn't
70
         * need to keep free lists or allocate this
71
         * memory.
72
         */
73
        queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL);
74
        if (q) {
75
                for (; nqueues; q++, nqueues--) {
76
                        SET_MAGIC(q, QUEUE_MAGIC_FREE);
77
                        q->SCpnt = NULL;
78
                        list_add(&q->list, &queue->free);
79
                }
80
        }
81
 
82
        return queue->alloc != NULL;
83
}
84
 
85
/*
86
 * Function: void queue_free (Queue_t *queue)
87
 * Purpose : free a queue
88
 * Params  : queue - queue to free
89
 */
90
void queue_free (Queue_t *queue)
91
{
92
        if (!list_empty(&queue->head))
93
                printk(KERN_WARNING "freeing non-empty queue %p\n", queue);
94
        if (queue->alloc)
95
                kfree(queue->alloc);
96
}
97
 
98
 
99
/*
100
 * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
101
 * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
102
 * Params  : queue - destination queue
103
 *           SCpnt - command to add
104
 *           head  - add command to head of queue
105
 * Returns : 0 on error, !0 on success
106
 */
107
int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
108
{
109
        unsigned long flags;
110
        struct list_head *l;
111
        QE_t *q;
112
        int ret = 0;
113
 
114
        spin_lock_irqsave(&queue->queue_lock, flags);
115
        if (list_empty(&queue->free))
116
                goto empty;
117
 
118
        l = queue->free.next;
119
        list_del(l);
120
 
121
        q = list_entry(l, QE_t, list);
122
        if (BAD_MAGIC(q, QUEUE_MAGIC_FREE))
123
                BUG();
124
 
125
        SET_MAGIC(q, QUEUE_MAGIC_USED);
126
        q->SCpnt = SCpnt;
127
 
128
        if (head)
129
                list_add(l, &queue->head);
130
        else
131
                list_add_tail(l, &queue->head);
132
 
133
        ret = 1;
134
empty:
135
        spin_unlock_irqrestore(&queue->queue_lock, flags);
136
        return ret;
137
}
138
 
139
static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
140
{
141
        QE_t *q;
142
 
143
        /*
144
         * Move the entry from the "used" list onto the "free" list
145
         */
146
        list_del(ent);
147
        q = list_entry(ent, QE_t, list);
148
        if (BAD_MAGIC(q, QUEUE_MAGIC_USED))
149
                BUG();
150
 
151
        SET_MAGIC(q, QUEUE_MAGIC_FREE);
152
        list_add(ent, &queue->free);
153
 
154
        return q->SCpnt;
155
}
156
 
157
/*
158
 * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
159
 * Purpose : remove a SCSI command from a queue
160
 * Params  : queue   - queue to remove command from
161
 *           exclude - bit array of target&lun which is busy
162
 * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
163
 */
164
Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, void *exclude)
165
{
166
        unsigned long flags;
167
        struct list_head *l;
168
        Scsi_Cmnd *SCpnt = NULL;
169
 
170
        spin_lock_irqsave(&queue->queue_lock, flags);
171
        list_for_each(l, &queue->head) {
172
                QE_t *q = list_entry(l, QE_t, list);
173
                if (!test_bit(q->SCpnt->target * 8 + q->SCpnt->lun, exclude)) {
174
                        SCpnt = __queue_remove(queue, l);
175
                        break;
176
                }
177
        }
178
        spin_unlock_irqrestore(&queue->queue_lock, flags);
179
 
180
        return SCpnt;
181
}
182
 
183
/*
184
 * Function: Scsi_Cmnd *queue_remove (queue)
185
 * Purpose : removes first SCSI command from a queue
186
 * Params  : queue   - queue to remove command from
187
 * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
188
 */
189
Scsi_Cmnd *queue_remove(Queue_t *queue)
190
{
191
        unsigned long flags;
192
        Scsi_Cmnd *SCpnt = NULL;
193
 
194
        spin_lock_irqsave(&queue->queue_lock, flags);
195
        if (!list_empty(&queue->head))
196
                SCpnt = __queue_remove(queue, queue->head.next);
197
        spin_unlock_irqrestore(&queue->queue_lock, flags);
198
 
199
        return SCpnt;
200
}
201
 
202
/*
203
 * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
204
 * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
205
 * Params  : queue  - queue to remove command from
206
 *           target - target that we want
207
 *           lun    - lun on device
208
 *           tag    - tag on device
209
 * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
210
 */
211
Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
212
{
213
        unsigned long flags;
214
        struct list_head *l;
215
        Scsi_Cmnd *SCpnt = NULL;
216
 
217
        spin_lock_irqsave(&queue->queue_lock, flags);
218
        list_for_each(l, &queue->head) {
219
                QE_t *q = list_entry(l, QE_t, list);
220
                if (q->SCpnt->target == target && q->SCpnt->lun == lun &&
221
                    q->SCpnt->tag == tag) {
222
                        SCpnt = __queue_remove(queue, l);
223
                        break;
224
                }
225
        }
226
        spin_unlock_irqrestore(&queue->queue_lock, flags);
227
 
228
        return SCpnt;
229
}
230
 
231
/*
232
 * Function: queue_remove_all_target(queue, target)
233
 * Purpose : remove all SCSI commands from the queue for a specified target
234
 * Params  : queue  - queue to remove command from
235
 *           target - target device id
236
 * Returns : nothing
237
 */
238
void queue_remove_all_target(Queue_t *queue, int target)
239
{
240
        unsigned long flags;
241
        struct list_head *l;
242
 
243
        spin_lock_irqsave(&queue->queue_lock, flags);
244
        list_for_each(l, &queue->head) {
245
                QE_t *q = list_entry(l, QE_t, list);
246
                if (q->SCpnt->target == target)
247
                        __queue_remove(queue, l);
248
        }
249
        spin_unlock_irqrestore(&queue->queue_lock, flags);
250
}
251
 
252
/*
253
 * Function: int queue_probetgtlun (queue, target, lun)
254
 * Purpose : check to see if we have a command in the queue for the specified
255
 *           target/lun.
256
 * Params  : queue  - queue to look in
257
 *           target - target we want to probe
258
 *           lun    - lun on target
259
 * Returns : 0 if not found, != 0 if found
260
 */
261
int queue_probetgtlun (Queue_t *queue, int target, int lun)
262
{
263
        unsigned long flags;
264
        struct list_head *l;
265
        int found = 0;
266
 
267
        spin_lock_irqsave(&queue->queue_lock, flags);
268
        list_for_each(l, &queue->head) {
269
                QE_t *q = list_entry(l, QE_t, list);
270
                if (q->SCpnt->target == target && q->SCpnt->lun == lun) {
271
                        found = 1;
272
                        break;
273
                }
274
        }
275
        spin_unlock_irqrestore(&queue->queue_lock, flags);
276
 
277
        return found;
278
}
279
 
280
/*
281
 * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
282
 * Purpose : remove a specific command from the queues
283
 * Params  : queue - queue to look in
284
 *           SCpnt - command to find
285
 * Returns : 0 if not found
286
 */
287
int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
288
{
289
        unsigned long flags;
290
        struct list_head *l;
291
        int found = 0;
292
 
293
        spin_lock_irqsave(&queue->queue_lock, flags);
294
        list_for_each(l, &queue->head) {
295
                QE_t *q = list_entry(l, QE_t, list);
296
                if (q->SCpnt == SCpnt) {
297
                        __queue_remove(queue, l);
298
                        found = 1;
299
                        break;
300
                }
301
        }
302
        spin_unlock_irqrestore(&queue->queue_lock, flags);
303
 
304
        return found;
305
}
306
 
307
EXPORT_SYMBOL(queue_initialise);
308
EXPORT_SYMBOL(queue_free);
309
EXPORT_SYMBOL(__queue_add);
310
EXPORT_SYMBOL(queue_remove);
311
EXPORT_SYMBOL(queue_remove_exclude);
312
EXPORT_SYMBOL(queue_remove_tgtluntag);
313
EXPORT_SYMBOL(queue_remove_cmd);
314
EXPORT_SYMBOL(queue_remove_all_target);
315
EXPORT_SYMBOL(queue_probetgtlun);
316
 
317
MODULE_AUTHOR("Russell King");
318
MODULE_DESCRIPTION("SCSI command queueing");
319
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.