0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/blkdev.h>
0016 #include <linux/kernel.h>
0017 #include <linux/string.h>
0018 #include <linux/slab.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/list.h>
0021 #include <linux/init.h>
0022
0023 #include <scsi/scsi.h>
0024 #include <scsi/scsi_cmnd.h>
0025 #include <scsi/scsi_device.h>
0026 #include <scsi/scsi_eh.h>
0027 #include <scsi/scsi_tcq.h>
0028
0029 #define DEBUG
0030
0031 typedef struct queue_entry {
0032 struct list_head list;
0033 struct scsi_cmnd *SCpnt;
0034 #ifdef DEBUG
0035 unsigned long magic;
0036 #endif
0037 } QE_t;
0038
0039 #ifdef DEBUG
0040 #define QUEUE_MAGIC_FREE 0xf7e1c9a3
0041 #define QUEUE_MAGIC_USED 0xf7e1cc33
0042
0043 #define SET_MAGIC(q,m) ((q)->magic = (m))
0044 #define BAD_MAGIC(q,m) ((q)->magic != (m))
0045 #else
0046 #define SET_MAGIC(q,m) do { } while (0)
0047 #define BAD_MAGIC(q,m) (0)
0048 #endif
0049
0050 #include "queue.h"
0051
0052 #define NR_QE 32
0053
0054
0055
0056
0057
0058
0059 int queue_initialise (Queue_t *queue)
0060 {
0061 unsigned int nqueues = NR_QE;
0062 QE_t *q;
0063
0064 spin_lock_init(&queue->queue_lock);
0065 INIT_LIST_HEAD(&queue->head);
0066 INIT_LIST_HEAD(&queue->free);
0067
0068
0069
0070
0071
0072
0073
0074 queue->alloc = q = kmalloc_array(nqueues, sizeof(QE_t), GFP_KERNEL);
0075 if (q) {
0076 for (; nqueues; q++, nqueues--) {
0077 SET_MAGIC(q, QUEUE_MAGIC_FREE);
0078 q->SCpnt = NULL;
0079 list_add(&q->list, &queue->free);
0080 }
0081 }
0082
0083 return queue->alloc != NULL;
0084 }
0085
0086
0087
0088
0089
0090
0091 void queue_free (Queue_t *queue)
0092 {
0093 if (!list_empty(&queue->head))
0094 printk(KERN_WARNING "freeing non-empty queue %p\n", queue);
0095 kfree(queue->alloc);
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
0108 {
0109 unsigned long flags;
0110 struct list_head *l;
0111 QE_t *q;
0112 int ret = 0;
0113
0114 spin_lock_irqsave(&queue->queue_lock, flags);
0115 if (list_empty(&queue->free))
0116 goto empty;
0117
0118 l = queue->free.next;
0119 list_del(l);
0120
0121 q = list_entry(l, QE_t, list);
0122 BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_FREE));
0123
0124 SET_MAGIC(q, QUEUE_MAGIC_USED);
0125 q->SCpnt = SCpnt;
0126
0127 if (head)
0128 list_add(l, &queue->head);
0129 else
0130 list_add_tail(l, &queue->head);
0131
0132 ret = 1;
0133 empty:
0134 spin_unlock_irqrestore(&queue->queue_lock, flags);
0135 return ret;
0136 }
0137
0138 static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
0139 {
0140 QE_t *q;
0141
0142
0143
0144
0145 list_del(ent);
0146 q = list_entry(ent, QE_t, list);
0147 BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_USED));
0148
0149 SET_MAGIC(q, QUEUE_MAGIC_FREE);
0150 list_add(ent, &queue->free);
0151
0152 return q->SCpnt;
0153 }
0154
0155
0156
0157
0158
0159
0160
0161
0162 struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
0163 {
0164 unsigned long flags;
0165 struct list_head *l;
0166 struct scsi_cmnd *SCpnt = NULL;
0167
0168 spin_lock_irqsave(&queue->queue_lock, flags);
0169 list_for_each(l, &queue->head) {
0170 QE_t *q = list_entry(l, QE_t, list);
0171 if (!test_bit(q->SCpnt->device->id * 8 +
0172 (u8)(q->SCpnt->device->lun & 0x7), exclude)) {
0173 SCpnt = __queue_remove(queue, l);
0174 break;
0175 }
0176 }
0177 spin_unlock_irqrestore(&queue->queue_lock, flags);
0178
0179 return SCpnt;
0180 }
0181
0182
0183
0184
0185
0186
0187
0188 struct scsi_cmnd *queue_remove(Queue_t *queue)
0189 {
0190 unsigned long flags;
0191 struct scsi_cmnd *SCpnt = NULL;
0192
0193 spin_lock_irqsave(&queue->queue_lock, flags);
0194 if (!list_empty(&queue->head))
0195 SCpnt = __queue_remove(queue, queue->head.next);
0196 spin_unlock_irqrestore(&queue->queue_lock, flags);
0197
0198 return SCpnt;
0199 }
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun,
0211 int tag)
0212 {
0213 unsigned long flags;
0214 struct list_head *l;
0215 struct scsi_cmnd *SCpnt = NULL;
0216
0217 spin_lock_irqsave(&queue->queue_lock, flags);
0218 list_for_each(l, &queue->head) {
0219 QE_t *q = list_entry(l, QE_t, list);
0220 if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun &&
0221 scsi_cmd_to_rq(q->SCpnt)->tag == tag) {
0222 SCpnt = __queue_remove(queue, l);
0223 break;
0224 }
0225 }
0226 spin_unlock_irqrestore(&queue->queue_lock, flags);
0227
0228 return SCpnt;
0229 }
0230
0231
0232
0233
0234
0235
0236
0237
0238 void queue_remove_all_target(Queue_t *queue, int target)
0239 {
0240 unsigned long flags;
0241 struct list_head *l;
0242
0243 spin_lock_irqsave(&queue->queue_lock, flags);
0244 list_for_each(l, &queue->head) {
0245 QE_t *q = list_entry(l, QE_t, list);
0246 if (q->SCpnt->device->id == target)
0247 __queue_remove(queue, l);
0248 }
0249 spin_unlock_irqrestore(&queue->queue_lock, flags);
0250 }
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 int queue_probetgtlun (Queue_t *queue, int target, int lun)
0262 {
0263 unsigned long flags;
0264 struct list_head *l;
0265 int found = 0;
0266
0267 spin_lock_irqsave(&queue->queue_lock, flags);
0268 list_for_each(l, &queue->head) {
0269 QE_t *q = list_entry(l, QE_t, list);
0270 if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun) {
0271 found = 1;
0272 break;
0273 }
0274 }
0275 spin_unlock_irqrestore(&queue->queue_lock, flags);
0276
0277 return found;
0278 }
0279
0280
0281
0282
0283
0284
0285
0286
0287 int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
0288 {
0289 unsigned long flags;
0290 struct list_head *l;
0291 int found = 0;
0292
0293 spin_lock_irqsave(&queue->queue_lock, flags);
0294 list_for_each(l, &queue->head) {
0295 QE_t *q = list_entry(l, QE_t, list);
0296 if (q->SCpnt == SCpnt) {
0297 __queue_remove(queue, l);
0298 found = 1;
0299 break;
0300 }
0301 }
0302 spin_unlock_irqrestore(&queue->queue_lock, flags);
0303
0304 return found;
0305 }
0306
0307 EXPORT_SYMBOL(queue_initialise);
0308 EXPORT_SYMBOL(queue_free);
0309 EXPORT_SYMBOL(__queue_add);
0310 EXPORT_SYMBOL(queue_remove);
0311 EXPORT_SYMBOL(queue_remove_exclude);
0312 EXPORT_SYMBOL(queue_remove_tgtluntag);
0313 EXPORT_SYMBOL(queue_remove_cmd);
0314 EXPORT_SYMBOL(queue_remove_all_target);
0315 EXPORT_SYMBOL(queue_probetgtlun);
0316
0317 MODULE_AUTHOR("Russell King");
0318 MODULE_DESCRIPTION("SCSI command queueing");
0319 MODULE_LICENSE("GPL");