blob: 20ae2b17df5862c166cc6b91f453567a7e08a749 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2** High Performance device driver for the Symbios 53C896 controller.
3**
4** Copyright (C) 1998-2001 Gerard Roudier <groudier@free.fr>
5**
6** This driver also supports all the Symbios 53C8XX controller family,
7** except 53C810 revisions < 16, 53C825 revisions < 16 and all
8** revisions of 53C815 controllers.
9**
10** This driver is based on the Linux port of the FreeBSD ncr driver.
11**
12** Copyright (C) 1994 Wolfgang Stanglmeier
13**
14**-----------------------------------------------------------------------------
15**
16** This program is free software; you can redistribute it and/or modify
17** it under the terms of the GNU General Public License as published by
18** the Free Software Foundation; either version 2 of the License, or
19** (at your option) any later version.
20**
21** This program is distributed in the hope that it will be useful,
22** but WITHOUT ANY WARRANTY; without even the implied warranty of
23** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24** GNU General Public License for more details.
25**
26** You should have received a copy of the GNU General Public License
27** along with this program; if not, write to the Free Software
28** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29**
30**-----------------------------------------------------------------------------
31**
32** The Linux port of the FreeBSD ncr driver has been achieved in
33** november 1995 by:
34**
35** Gerard Roudier <groudier@free.fr>
36**
37** Being given that this driver originates from the FreeBSD version, and
38** in order to keep synergy on both, any suggested enhancements and corrections
39** received on Linux are automatically a potential candidate for the FreeBSD
40** version.
41**
42** The original driver has been written for 386bsd and FreeBSD by
43** Wolfgang Stanglmeier <wolf@cologne.de>
44** Stefan Esser <se@mi.Uni-Koeln.de>
45**
46**-----------------------------------------------------------------------------
47**
48** Major contributions:
49** --------------------
50**
51** NVRAM detection and reading.
52** Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
53**
54*******************************************************************************
55*/
56
57/*==========================================================
58**
59** Debugging tags
60**
61**==========================================================
62*/
63
64#define DEBUG_ALLOC (0x0001)
65#define DEBUG_PHASE (0x0002)
66#define DEBUG_QUEUE (0x0008)
67#define DEBUG_RESULT (0x0010)
68#define DEBUG_POINTER (0x0020)
69#define DEBUG_SCRIPT (0x0040)
70#define DEBUG_TINY (0x0080)
71#define DEBUG_TIMING (0x0100)
72#define DEBUG_NEGO (0x0200)
73#define DEBUG_TAGS (0x0400)
74#define DEBUG_SCATTER (0x0800)
75#define DEBUG_IC (0x1000)
76
77/*
78** Enable/Disable debug messages.
79** Can be changed at runtime too.
80*/
81
82#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
83static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
84 #define DEBUG_FLAGS ncr_debug
85#else
86 #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
87#endif
88
89static inline struct list_head *ncr_list_pop(struct list_head *head)
90{
91 if (!list_empty(head)) {
92 struct list_head *elem = head->next;
93
94 list_del(elem);
95 return elem;
96 }
97
98 return NULL;
99}
100
101#ifdef __sparc__
102#include <asm/irq.h>
103#endif
104
105/*==========================================================
106**
107** Simple power of two buddy-like allocator.
108**
109** This simple code is not intended to be fast, but to
110** provide power of 2 aligned memory allocations.
111** Since the SCRIPTS processor only supplies 8 bit
112** arithmetic, this allocator allows simple and fast
113** address calculations from the SCRIPTS code.
114** In addition, cache line alignment is guaranteed for
115** power of 2 cache line size.
116** Enhanced in linux-2.3.44 to provide a memory pool
117** per pcidev to support dynamic dma mapping. (I would
118** have preferred a real bus astraction, btw).
119**
120**==========================================================
121*/
122
123#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
124#if PAGE_SIZE >= 8192
125#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */
126#else
127#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */
128#endif
129#define MEMO_FREE_UNUSED /* Free unused pages immediately */
130#define MEMO_WARN 1
131#define MEMO_GFP_FLAGS GFP_ATOMIC
132#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER)
133#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT)
134#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1)
135
136typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */
137typedef struct device *m_bush_t; /* Something that addresses DMAable */
138
139typedef struct m_link { /* Link between free memory chunks */
140 struct m_link *next;
141} m_link_s;
142
143typedef struct m_vtob { /* Virtual to Bus address translation */
144 struct m_vtob *next;
145 m_addr_t vaddr;
146 m_addr_t baddr;
147} m_vtob_s;
148#define VTOB_HASH_SHIFT 5
149#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT)
150#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1)
151#define VTOB_HASH_CODE(m) \
152 ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
153
154typedef struct m_pool { /* Memory pool of a given kind */
155 m_bush_t bush;
156 m_addr_t (*getp)(struct m_pool *);
157 void (*freep)(struct m_pool *, m_addr_t);
158 int nump;
159 m_vtob_s *(vtob[VTOB_HASH_SIZE]);
160 struct m_pool *next;
161 struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
162} m_pool_s;
163
164static void *___m_alloc(m_pool_s *mp, int size)
165{
166 int i = 0;
167 int s = (1 << MEMO_SHIFT);
168 int j;
169 m_addr_t a;
170 m_link_s *h = mp->h;
171
172 if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
173 return NULL;
174
175 while (size > s) {
176 s <<= 1;
177 ++i;
178 }
179
180 j = i;
181 while (!h[j].next) {
182 if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
183 h[j].next = (m_link_s *)mp->getp(mp);
184 if (h[j].next)
185 h[j].next->next = NULL;
186 break;
187 }
188 ++j;
189 s <<= 1;
190 }
191 a = (m_addr_t) h[j].next;
192 if (a) {
193 h[j].next = h[j].next->next;
194 while (j > i) {
195 j -= 1;
196 s >>= 1;
197 h[j].next = (m_link_s *) (a+s);
198 h[j].next->next = NULL;
199 }
200 }
201#ifdef DEBUG
202 printk("___m_alloc(%d) = %p\n", size, (void *) a);
203#endif
204 return (void *) a;
205}
206
207static void ___m_free(m_pool_s *mp, void *ptr, int size)
208{
209 int i = 0;
210 int s = (1 << MEMO_SHIFT);
211 m_link_s *q;
212 m_addr_t a, b;
213 m_link_s *h = mp->h;
214
215#ifdef DEBUG
216 printk("___m_free(%p, %d)\n", ptr, size);
217#endif
218
219 if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
220 return;
221
222 while (size > s) {
223 s <<= 1;
224 ++i;
225 }
226
227 a = (m_addr_t) ptr;
228
229 while (1) {
230#ifdef MEMO_FREE_UNUSED
231 if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
232 mp->freep(mp, a);
233 break;
234 }
235#endif
236 b = a ^ s;
237 q = &h[i];
238 while (q->next && q->next != (m_link_s *) b) {
239 q = q->next;
240 }
241 if (!q->next) {
242 ((m_link_s *) a)->next = h[i].next;
243 h[i].next = (m_link_s *) a;
244 break;
245 }
246 q->next = q->next->next;
247 a = a & b;
248 s <<= 1;
249 ++i;
250 }
251}
252
253static DEFINE_SPINLOCK(ncr53c8xx_lock);
254
255static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
256{
257 void *p;
258
259 p = ___m_alloc(mp, size);
260
261 if (DEBUG_FLAGS & DEBUG_ALLOC)
262 printk ("new %-10s[%4d] @%p.\n", name, size, p);
263
264 if (p)
265 memset(p, 0, size);
266 else if (uflags & MEMO_WARN)
267 printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
268
269 return p;
270}
271
272#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN)
273
274static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
275{
276 if (DEBUG_FLAGS & DEBUG_ALLOC)
277 printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
278
279 ___m_free(mp, ptr, size);
280
281}
282
283/*
284 * With pci bus iommu support, we use a default pool of unmapped memory
285 * for memory we donnot need to DMA from/to and one pool per pcidev for
286 * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
287 */
288
289static m_addr_t ___mp0_getp(m_pool_s *mp)
290{
291 m_addr_t m = __get_free_pages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER);
292 if (m)
293 ++mp->nump;
294 return m;
295}
296
297static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
298{
299 free_pages(m, MEMO_PAGE_ORDER);
300 --mp->nump;
301}
302
303static m_pool_s mp0 = {NULL, ___mp0_getp, ___mp0_freep};
304
305/*
306 * DMAable pools.
307 */
308
309/*
310 * With pci bus iommu support, we maintain one pool per pcidev and a
311 * hashed reverse table for virtual to bus physical address translations.
312 */
313static m_addr_t ___dma_getp(m_pool_s *mp)
314{
315 m_addr_t vp;
316 m_vtob_s *vbp;
317
318 vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
319 if (vbp) {
320 dma_addr_t daddr;
321 vp = (m_addr_t) dma_alloc_coherent(mp->bush,
322 PAGE_SIZE<<MEMO_PAGE_ORDER,
323 &daddr, GFP_ATOMIC);
324 if (vp) {
325 int hc = VTOB_HASH_CODE(vp);
326 vbp->vaddr = vp;
327 vbp->baddr = daddr;
328 vbp->next = mp->vtob[hc];
329 mp->vtob[hc] = vbp;
330 ++mp->nump;
331 return vp;
332 }
333 }
334 if (vbp)
335 __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
336 return 0;
337}
338
339static void ___dma_freep(m_pool_s *mp, m_addr_t m)
340{
341 m_vtob_s **vbpp, *vbp;
342 int hc = VTOB_HASH_CODE(m);
343
344 vbpp = &mp->vtob[hc];
345 while (*vbpp && (*vbpp)->vaddr != m)
346 vbpp = &(*vbpp)->next;
347 if (*vbpp) {
348 vbp = *vbpp;
349 *vbpp = (*vbpp)->next;
350 dma_free_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
351 (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
352 __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
353 --mp->nump;
354 }
355}
356
357static inline m_pool_s *___get_dma_pool(m_bush_t bush)
358{
359 m_pool_s *mp;
360 for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
361 return mp;
362}
363
364static m_pool_s *___cre_dma_pool(m_bush_t bush)
365{
366 m_pool_s *mp;
367 mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
368 if (mp) {
369 memset(mp, 0, sizeof(*mp));
370 mp->bush = bush;
371 mp->getp = ___dma_getp;
372 mp->freep = ___dma_freep;
373 mp->next = mp0.next;
374 mp0.next = mp;
375 }
376 return mp;
377}
378
379static void ___del_dma_pool(m_pool_s *p)
380{
381 struct m_pool **pp = &mp0.next;
382
383 while (*pp && *pp != p)
384 pp = &(*pp)->next;
385 if (*pp) {
386 *pp = (*pp)->next;
387 __m_free(&mp0, p, sizeof(*p), "MPOOL");
388 }
389}
390
391static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
392{
393 u_long flags;
394 struct m_pool *mp;
395 void *m = NULL;
396
397 spin_lock_irqsave(&ncr53c8xx_lock, flags);
398 mp = ___get_dma_pool(bush);
399 if (!mp)
400 mp = ___cre_dma_pool(bush);
401 if (mp)
402 m = __m_calloc(mp, size, name);
403 if (mp && !mp->nump)
404 ___del_dma_pool(mp);
405 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
406
407 return m;
408}
409
410static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
411{
412 u_long flags;
413 struct m_pool *mp;
414
415 spin_lock_irqsave(&ncr53c8xx_lock, flags);
416 mp = ___get_dma_pool(bush);
417 if (mp)
418 __m_free(mp, m, size, name);
419 if (mp && !mp->nump)
420 ___del_dma_pool(mp);
421 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
422}
423
424static m_addr_t __vtobus(m_bush_t bush, void *m)
425{
426 u_long flags;
427 m_pool_s *mp;
428 int hc = VTOB_HASH_CODE(m);
429 m_vtob_s *vp = NULL;
430 m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
431
432 spin_lock_irqsave(&ncr53c8xx_lock, flags);
433 mp = ___get_dma_pool(bush);
434 if (mp) {
435 vp = mp->vtob[hc];
436 while (vp && (m_addr_t) vp->vaddr != a)
437 vp = vp->next;
438 }
439 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
440 return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
441}
442
443#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->dev, s, n)
444#define _m_free_dma(np, p, s, n) __m_free_dma(np->dev, p, s, n)
445#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n)
446#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n)
447#define _vtobus(np, p) __vtobus(np->dev, p)
448#define vtobus(p) _vtobus(np, p)
449
450/*
451 * Deal with DMA mapping/unmapping.
452 */
453
454/* To keep track of the dma mapping (sg/single) that has been set */
455#define __data_mapped SCp.phase
456#define __data_mapping SCp.have_data_in
457
458static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd)
459{
460 switch(cmd->__data_mapped) {
461 case 2:
462 dma_unmap_sg(dev, cmd->buffer, cmd->use_sg,
463 cmd->sc_data_direction);
464 break;
465 case 1:
466 dma_unmap_single(dev, cmd->__data_mapping,
467 cmd->request_bufflen,
468 cmd->sc_data_direction);
469 break;
470 }
471 cmd->__data_mapped = 0;
472}
473
474static u_long __map_scsi_single_data(struct device *dev, struct scsi_cmnd *cmd)
475{
476 dma_addr_t mapping;
477
478 if (cmd->request_bufflen == 0)
479 return 0;
480
481 mapping = dma_map_single(dev, cmd->request_buffer,
482 cmd->request_bufflen,
483 cmd->sc_data_direction);
484 cmd->__data_mapped = 1;
485 cmd->__data_mapping = mapping;
486
487 return mapping;
488}
489
490static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
491{
492 int use_sg;
493
494 if (cmd->use_sg == 0)
495 return 0;
496
497 use_sg = dma_map_sg(dev, cmd->buffer, cmd->use_sg,
498 cmd->sc_data_direction);
499 cmd->__data_mapped = 2;
500 cmd->__data_mapping = use_sg;
501
502 return use_sg;
503}
504
505#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd)
506#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->dev, cmd)
507#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd)
508
509/*==========================================================
510**
511** Driver setup.
512**
513** This structure is initialized from linux config
514** options. It can be overridden at boot-up by the boot
515** command line.
516**
517**==========================================================
518*/
519static struct ncr_driver_setup
520 driver_setup = SCSI_NCR_DRIVER_SETUP;
521
522#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
523static struct ncr_driver_setup
524 driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
525#endif
526
527#define initverbose (driver_setup.verbose)
528#define bootverbose (np->verbose)
529
530
531/*===================================================================
532**
533** Driver setup from the boot command line
534**
535**===================================================================
536*/
537
538#ifdef MODULE
539#define ARG_SEP ' '
540#else
541#define ARG_SEP ','
542#endif
543
544#define OPT_TAGS 1
545#define OPT_MASTER_PARITY 2
546#define OPT_SCSI_PARITY 3
547#define OPT_DISCONNECTION 4
548#define OPT_SPECIAL_FEATURES 5
549#define OPT_UNUSED_1 6
550#define OPT_FORCE_SYNC_NEGO 7
551#define OPT_REVERSE_PROBE 8
552#define OPT_DEFAULT_SYNC 9
553#define OPT_VERBOSE 10
554#define OPT_DEBUG 11
555#define OPT_BURST_MAX 12
556#define OPT_LED_PIN 13
557#define OPT_MAX_WIDE 14
558#define OPT_SETTLE_DELAY 15
559#define OPT_DIFF_SUPPORT 16
560#define OPT_IRQM 17
561#define OPT_PCI_FIX_UP 18
562#define OPT_BUS_CHECK 19
563#define OPT_OPTIMIZE 20
564#define OPT_RECOVERY 21
565#define OPT_SAFE_SETUP 22
566#define OPT_USE_NVRAM 23
567#define OPT_EXCLUDE 24
568#define OPT_HOST_ID 25
569
570#ifdef SCSI_NCR_IARB_SUPPORT
571#define OPT_IARB 26
572#endif
573
574static char setup_token[] __initdata =
575 "tags:" "mpar:"
576 "spar:" "disc:"
577 "specf:" "ultra:"
578 "fsn:" "revprob:"
579 "sync:" "verb:"
580 "debug:" "burst:"
581 "led:" "wide:"
582 "settle:" "diff:"
583 "irqm:" "pcifix:"
584 "buschk:" "optim:"
585 "recovery:"
586 "safe:" "nvram:"
587 "excl:" "hostid:"
588#ifdef SCSI_NCR_IARB_SUPPORT
589 "iarb:"
590#endif
591 ; /* DONNOT REMOVE THIS ';' */
592
593#ifdef MODULE
594#define ARG_SEP ' '
595#else
596#define ARG_SEP ','
597#endif
598
599static int __init get_setup_token(char *p)
600{
601 char *cur = setup_token;
602 char *pc;
603 int i = 0;
604
605 while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
606 ++pc;
607 ++i;
608 if (!strncmp(p, cur, pc - cur))
609 return i;
610 cur = pc;
611 }
612 return 0;
613}
614
615
616static int __init sym53c8xx__setup(char *str)
617{
618#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
619 char *cur = str;
620 char *pc, *pv;
621 int i, val, c;
622 int xi = 0;
623
624 while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
625 char *pe;
626
627 val = 0;
628 pv = pc;
629 c = *++pv;
630
631 if (c == 'n')
632 val = 0;
633 else if (c == 'y')
634 val = 1;
635 else
636 val = (int) simple_strtoul(pv, &pe, 0);
637
638 switch (get_setup_token(cur)) {
639 case OPT_TAGS:
640 driver_setup.default_tags = val;
641 if (pe && *pe == '/') {
642 i = 0;
643 while (*pe && *pe != ARG_SEP &&
644 i < sizeof(driver_setup.tag_ctrl)-1) {
645 driver_setup.tag_ctrl[i++] = *pe++;
646 }
647 driver_setup.tag_ctrl[i] = '\0';
648 }
649 break;
650 case OPT_MASTER_PARITY:
651 driver_setup.master_parity = val;
652 break;
653 case OPT_SCSI_PARITY:
654 driver_setup.scsi_parity = val;
655 break;
656 case OPT_DISCONNECTION:
657 driver_setup.disconnection = val;
658 break;
659 case OPT_SPECIAL_FEATURES:
660 driver_setup.special_features = val;
661 break;
662 case OPT_FORCE_SYNC_NEGO:
663 driver_setup.force_sync_nego = val;
664 break;
665 case OPT_REVERSE_PROBE:
666 driver_setup.reverse_probe = val;
667 break;
668 case OPT_DEFAULT_SYNC:
669 driver_setup.default_sync = val;
670 break;
671 case OPT_VERBOSE:
672 driver_setup.verbose = val;
673 break;
674 case OPT_DEBUG:
675 driver_setup.debug = val;
676 break;
677 case OPT_BURST_MAX:
678 driver_setup.burst_max = val;
679 break;
680 case OPT_LED_PIN:
681 driver_setup.led_pin = val;
682 break;
683 case OPT_MAX_WIDE:
684 driver_setup.max_wide = val? 1:0;
685 break;
686 case OPT_SETTLE_DELAY:
687 driver_setup.settle_delay = val;
688 break;
689 case OPT_DIFF_SUPPORT:
690 driver_setup.diff_support = val;
691 break;
692 case OPT_IRQM:
693 driver_setup.irqm = val;
694 break;
695 case OPT_PCI_FIX_UP:
696 driver_setup.pci_fix_up = val;
697 break;
698 case OPT_BUS_CHECK:
699 driver_setup.bus_check = val;
700 break;
701 case OPT_OPTIMIZE:
702 driver_setup.optimize = val;
703 break;
704 case OPT_RECOVERY:
705 driver_setup.recovery = val;
706 break;
707 case OPT_USE_NVRAM:
708 driver_setup.use_nvram = val;
709 break;
710 case OPT_SAFE_SETUP:
711 memcpy(&driver_setup, &driver_safe_setup,
712 sizeof(driver_setup));
713 break;
714 case OPT_EXCLUDE:
715 if (xi < SCSI_NCR_MAX_EXCLUDES)
716 driver_setup.excludes[xi++] = val;
717 break;
718 case OPT_HOST_ID:
719 driver_setup.host_id = val;
720 break;
721#ifdef SCSI_NCR_IARB_SUPPORT
722 case OPT_IARB:
723 driver_setup.iarb = val;
724 break;
725#endif
726 default:
727 printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
728 break;
729 }
730
731 if ((cur = strchr(cur, ARG_SEP)) != NULL)
732 ++cur;
733 }
734#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
735 return 1;
736}
737
738/*===================================================================
739**
740** Get device queue depth from boot command line.
741**
742**===================================================================
743*/
744#define DEF_DEPTH (driver_setup.default_tags)
745#define ALL_TARGETS -2
746#define NO_TARGET -1
747#define ALL_LUNS -2
748#define NO_LUN -1
749
750static int device_queue_depth(int unit, int target, int lun)
751{
752 int c, h, t, u, v;
753 char *p = driver_setup.tag_ctrl;
754 char *ep;
755
756 h = -1;
757 t = NO_TARGET;
758 u = NO_LUN;
759 while ((c = *p++) != 0) {
760 v = simple_strtoul(p, &ep, 0);
761 switch(c) {
762 case '/':
763 ++h;
764 t = ALL_TARGETS;
765 u = ALL_LUNS;
766 break;
767 case 't':
768 if (t != target)
769 t = (target == v) ? v : NO_TARGET;
770 u = ALL_LUNS;
771 break;
772 case 'u':
773 if (u != lun)
774 u = (lun == v) ? v : NO_LUN;
775 break;
776 case 'q':
777 if (h == unit &&
778 (t == ALL_TARGETS || t == target) &&
779 (u == ALL_LUNS || u == lun))
780 return v;
781 break;
782 case '-':
783 t = ALL_TARGETS;
784 u = ALL_LUNS;
785 break;
786 default:
787 break;
788 }
789 p = ep;
790 }
791 return DEF_DEPTH;
792}