]> err.no Git - linux-2.6/blob - drivers/scsi/aic7xxx/aiclib.c
Merge HEAD from ../scsi-misc-2.6-tmp
[linux-2.6] / drivers / scsi / aic7xxx / aiclib.c
1 /*
2  * Implementation of Utility functions for all SCSI device types.
3  *
4  * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
5  * Copyright (c) 1997, 1998 Kenneth D. Merry.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $
30  * $Id$
31  */
32
33 #include "aiclib.h"
34
35
36 /*
37  * Table of syncrates that don't follow the "divisible by 4"
38  * rule. This table will be expanded in future SCSI specs.
39  */
40 static struct {
41         u_int period_factor;
42         u_int period;   /* in 100ths of ns */
43 } scsi_syncrates[] = {
44         { 0x08, 625 },  /* FAST-160 */
45         { 0x09, 1250 }, /* FAST-80 */
46         { 0x0a, 2500 }, /* FAST-40 40MHz */
47         { 0x0b, 3030 }, /* FAST-40 33MHz */
48         { 0x0c, 5000 }  /* FAST-20 */
49 };
50
51 /*
52  * Return the frequency in kHz corresponding to the given
53  * sync period factor.
54  */
55 u_int
56 aic_calc_syncsrate(u_int period_factor)
57 {
58         int i;
59         int num_syncrates;
60
61         num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
62         /* See if the period is in the "exception" table */
63         for (i = 0; i < num_syncrates; i++) {
64
65                 if (period_factor == scsi_syncrates[i].period_factor) {
66                         /* Period in kHz */
67                         return (100000000 / scsi_syncrates[i].period);
68                 }
69         }
70
71         /*
72          * Wasn't in the table, so use the standard
73          * 4 times conversion.
74          */
75         return (10000000 / (period_factor * 4 * 10));
76 }
77
78 char *
79 aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
80                        aic_option_callback_t *callback, u_long callback_arg)
81 {
82         char    *tok_end;
83         char    *tok_end2;
84         int      i;
85         int      instance;
86         int      targ;
87         int      done;
88         char     tok_list[] = {'.', ',', '{', '}', '\0'};
89
90         /* All options use a ':' name/arg separator */
91         if (*opt_arg != ':')
92                 return (opt_arg);
93         opt_arg++;
94         instance = -1;
95         targ = -1;
96         done = FALSE;
97         /*
98          * Restore separator that may be in
99          * the middle of our option argument.
100          */
101         tok_end = strchr(opt_arg, '\0');
102         if (tok_end < end)
103                 *tok_end = ',';
104         while (!done) {
105                 switch (*opt_arg) {
106                 case '{':
107                         if (instance == -1) {
108                                 instance = 0;
109                         } else {
110                                 if (depth > 1) {
111                                         if (targ == -1)
112                                                 targ = 0;
113                                 } else {
114                                         printf("Malformed Option %s\n",
115                                                opt_name);
116                                         done = TRUE;
117                                 }
118                         }
119                         opt_arg++;
120                         break;
121                 case '}':
122                         if (targ != -1)
123                                 targ = -1;
124                         else if (instance != -1)
125                                 instance = -1;
126                         opt_arg++;
127                         break;
128                 case ',':
129                 case '.':
130                         if (instance == -1)
131                                 done = TRUE;
132                         else if (targ >= 0)
133                                 targ++;
134                         else if (instance >= 0)
135                                 instance++;
136                         opt_arg++;
137                         break;
138                 case '\0':
139                         done = TRUE;
140                         break;
141                 default:
142                         tok_end = end;
143                         for (i = 0; tok_list[i]; i++) {
144                                 tok_end2 = strchr(opt_arg, tok_list[i]);
145                                 if ((tok_end2) && (tok_end2 < tok_end))
146                                         tok_end = tok_end2;
147                         }
148                         callback(callback_arg, instance, targ,
149                                  simple_strtol(opt_arg, NULL, 0));
150                         opt_arg = tok_end;
151                         break;
152                 }
153         }
154         return (opt_arg);
155 }