aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c96
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c45
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c89
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c45
-rw-r--r--drivers/scsi/aic7xxx/aiclib.c121
-rw-r--r--drivers/scsi/aic7xxx/aiclib.h22
6 files changed, 253 insertions, 165 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 3feb739cd554..6b6d4e287793 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -48,12 +48,6 @@
48 48
49static struct scsi_transport_template *ahd_linux_transport_template = NULL; 49static struct scsi_transport_template *ahd_linux_transport_template = NULL;
50 50
51/*
52 * Include aiclib.c as part of our
53 * "module dependencies are hard" work around.
54 */
55#include "aiclib.c"
56
57#include <linux/init.h> /* __setup */ 51#include <linux/init.h> /* __setup */
58#include <linux/mm.h> /* For fetching system memory size */ 52#include <linux/mm.h> /* For fetching system memory size */
59#include <linux/blkdev.h> /* For block_size() */ 53#include <linux/blkdev.h> /* For block_size() */
@@ -372,8 +366,6 @@ static int ahd_linux_run_command(struct ahd_softc*,
372 struct ahd_linux_device *, 366 struct ahd_linux_device *,
373 struct scsi_cmnd *); 367 struct scsi_cmnd *);
374static void ahd_linux_setup_tag_info_global(char *p); 368static void ahd_linux_setup_tag_info_global(char *p);
375static aic_option_callback_t ahd_linux_setup_tag_info;
376static aic_option_callback_t ahd_linux_setup_iocell_info;
377static int aic79xx_setup(char *c); 369static int aic79xx_setup(char *c);
378 370
379static int ahd_linux_unit; 371static int ahd_linux_unit;
@@ -907,6 +899,86 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
907 } 899 }
908} 900}
909 901
902static char *
903ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
904 void (*callback)(u_long, int, int, int32_t),
905 u_long callback_arg)
906{
907 char *tok_end;
908 char *tok_end2;
909 int i;
910 int instance;
911 int targ;
912 int done;
913 char tok_list[] = {'.', ',', '{', '}', '\0'};
914
915 /* All options use a ':' name/arg separator */
916 if (*opt_arg != ':')
917 return (opt_arg);
918 opt_arg++;
919 instance = -1;
920 targ = -1;
921 done = FALSE;
922 /*
923 * Restore separator that may be in
924 * the middle of our option argument.
925 */
926 tok_end = strchr(opt_arg, '\0');
927 if (tok_end < end)
928 *tok_end = ',';
929 while (!done) {
930 switch (*opt_arg) {
931 case '{':
932 if (instance == -1) {
933 instance = 0;
934 } else {
935 if (depth > 1) {
936 if (targ == -1)
937 targ = 0;
938 } else {
939 printf("Malformed Option %s\n",
940 opt_name);
941 done = TRUE;
942 }
943 }
944 opt_arg++;
945 break;
946 case '}':
947 if (targ != -1)
948 targ = -1;
949 else if (instance != -1)
950 instance = -1;
951 opt_arg++;
952 break;
953 case ',':
954 case '.':
955 if (instance == -1)
956 done = TRUE;
957 else if (targ >= 0)
958 targ++;
959 else if (instance >= 0)
960 instance++;
961 opt_arg++;
962 break;
963 case '\0':
964 done = TRUE;
965 break;
966 default:
967 tok_end = end;
968 for (i = 0; tok_list[i]; i++) {
969 tok_end2 = strchr(opt_arg, tok_list[i]);
970 if ((tok_end2) && (tok_end2 < tok_end))
971 tok_end = tok_end2;
972 }
973 callback(callback_arg, instance, targ,
974 simple_strtol(opt_arg, NULL, 0));
975 opt_arg = tok_end;
976 break;
977 }
978 }
979 return (opt_arg);
980}
981
910/* 982/*
911 * Handle Linux boot parameters. This routine allows for assigning a value 983 * Handle Linux boot parameters. This routine allows for assigning a value
912 * to a parameter with a ':' between the parameter and the value. 984 * to a parameter with a ':' between the parameter and the value.
@@ -964,18 +1036,18 @@ aic79xx_setup(char *s)
964 if (strncmp(p, "global_tag_depth", n) == 0) { 1036 if (strncmp(p, "global_tag_depth", n) == 0) {
965 ahd_linux_setup_tag_info_global(p + n); 1037 ahd_linux_setup_tag_info_global(p + n);
966 } else if (strncmp(p, "tag_info", n) == 0) { 1038 } else if (strncmp(p, "tag_info", n) == 0) {
967 s = aic_parse_brace_option("tag_info", p + n, end, 1039 s = ahd_parse_brace_option("tag_info", p + n, end,
968 2, ahd_linux_setup_tag_info, 0); 1040 2, ahd_linux_setup_tag_info, 0);
969 } else if (strncmp(p, "slewrate", n) == 0) { 1041 } else if (strncmp(p, "slewrate", n) == 0) {
970 s = aic_parse_brace_option("slewrate", 1042 s = ahd_parse_brace_option("slewrate",
971 p + n, end, 1, ahd_linux_setup_iocell_info, 1043 p + n, end, 1, ahd_linux_setup_iocell_info,
972 AIC79XX_SLEWRATE_INDEX); 1044 AIC79XX_SLEWRATE_INDEX);
973 } else if (strncmp(p, "precomp", n) == 0) { 1045 } else if (strncmp(p, "precomp", n) == 0) {
974 s = aic_parse_brace_option("precomp", 1046 s = ahd_parse_brace_option("precomp",
975 p + n, end, 1, ahd_linux_setup_iocell_info, 1047 p + n, end, 1, ahd_linux_setup_iocell_info,
976 AIC79XX_PRECOMP_INDEX); 1048 AIC79XX_PRECOMP_INDEX);
977 } else if (strncmp(p, "amplitude", n) == 0) { 1049 } else if (strncmp(p, "amplitude", n) == 0) {
978 s = aic_parse_brace_option("amplitude", 1050 s = ahd_parse_brace_option("amplitude",
979 p + n, end, 1, ahd_linux_setup_iocell_info, 1051 p + n, end, 1, ahd_linux_setup_iocell_info,
980 AIC79XX_AMPLITUDE_INDEX); 1052 AIC79XX_AMPLITUDE_INDEX);
981 } else if (p[n] == ':') { 1053 } else if (p[n] == ':') {
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 32be1f55998c..39a27840fce6 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -53,6 +53,49 @@ static void ahd_dump_device_state(struct info_str *info,
53static int ahd_proc_write_seeprom(struct ahd_softc *ahd, 53static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
54 char *buffer, int length); 54 char *buffer, int length);
55 55
56/*
57 * Table of syncrates that don't follow the "divisible by 4"
58 * rule. This table will be expanded in future SCSI specs.
59 */
60static struct {
61 u_int period_factor;
62 u_int period; /* in 100ths of ns */
63} scsi_syncrates[] = {
64 { 0x08, 625 }, /* FAST-160 */
65 { 0x09, 1250 }, /* FAST-80 */
66 { 0x0a, 2500 }, /* FAST-40 40MHz */
67 { 0x0b, 3030 }, /* FAST-40 33MHz */
68 { 0x0c, 5000 } /* FAST-20 */
69};
70
71/*
72 * Return the frequency in kHz corresponding to the given
73 * sync period factor.
74 */
75static u_int
76ahd_calc_syncsrate(u_int period_factor)
77{
78 int i;
79 int num_syncrates;
80
81 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
82 /* See if the period is in the "exception" table */
83 for (i = 0; i < num_syncrates; i++) {
84
85 if (period_factor == scsi_syncrates[i].period_factor) {
86 /* Period in kHz */
87 return (100000000 / scsi_syncrates[i].period);
88 }
89 }
90
91 /*
92 * Wasn't in the table, so use the standard
93 * 4 times conversion.
94 */
95 return (10000000 / (period_factor * 4 * 10));
96}
97
98
56static void 99static void
57copy_mem_info(struct info_str *info, char *data, int len) 100copy_mem_info(struct info_str *info, char *data, int len)
58{ 101{
@@ -109,7 +152,7 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
109 speed = 3300; 152 speed = 3300;
110 freq = 0; 153 freq = 0;
111 if (tinfo->offset != 0) { 154 if (tinfo->offset != 0) {
112 freq = aic_calc_syncsrate(tinfo->period); 155 freq = ahd_calc_syncsrate(tinfo->period);
113 speed = freq; 156 speed = freq;
114 } 157 }
115 speed *= (0x01 << tinfo->width); 158 speed *= (0x01 << tinfo->width);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 22434849de48..4096d523d08d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -125,12 +125,6 @@
125 125
126static struct scsi_transport_template *ahc_linux_transport_template = NULL; 126static struct scsi_transport_template *ahc_linux_transport_template = NULL;
127 127
128/*
129 * Include aiclib.c as part of our
130 * "module dependencies are hard" work around.
131 */
132#include "aiclib.c"
133
134#include <linux/init.h> /* __setup */ 128#include <linux/init.h> /* __setup */
135#include <linux/mm.h> /* For fetching system memory size */ 129#include <linux/mm.h> /* For fetching system memory size */
136#include <linux/blkdev.h> /* For block_size() */ 130#include <linux/blkdev.h> /* For block_size() */
@@ -391,7 +385,6 @@ static int ahc_linux_run_command(struct ahc_softc*,
391 struct ahc_linux_device *, 385 struct ahc_linux_device *,
392 struct scsi_cmnd *); 386 struct scsi_cmnd *);
393static void ahc_linux_setup_tag_info_global(char *p); 387static void ahc_linux_setup_tag_info_global(char *p);
394static aic_option_callback_t ahc_linux_setup_tag_info;
395static int aic7xxx_setup(char *s); 388static int aic7xxx_setup(char *s);
396 389
397static int ahc_linux_unit; 390static int ahc_linux_unit;
@@ -920,6 +913,86 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
920 } 913 }
921} 914}
922 915
916static char *
917ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
918 void (*callback)(u_long, int, int, int32_t),
919 u_long callback_arg)
920{
921 char *tok_end;
922 char *tok_end2;
923 int i;
924 int instance;
925 int targ;
926 int done;
927 char tok_list[] = {'.', ',', '{', '}', '\0'};
928
929 /* All options use a ':' name/arg separator */
930 if (*opt_arg != ':')
931 return (opt_arg);
932 opt_arg++;
933 instance = -1;
934 targ = -1;
935 done = FALSE;
936 /*
937 * Restore separator that may be in
938 * the middle of our option argument.
939 */
940 tok_end = strchr(opt_arg, '\0');
941 if (tok_end < end)
942 *tok_end = ',';
943 while (!done) {
944 switch (*opt_arg) {
945 case '{':
946 if (instance == -1) {
947 instance = 0;
948 } else {
949 if (depth > 1) {
950 if (targ == -1)
951 targ = 0;
952 } else {
953 printf("Malformed Option %s\n",
954 opt_name);
955 done = TRUE;
956 }
957 }
958 opt_arg++;
959 break;
960 case '}':
961 if (targ != -1)
962 targ = -1;
963 else if (instance != -1)
964 instance = -1;
965 opt_arg++;
966 break;
967 case ',':
968 case '.':
969 if (instance == -1)
970 done = TRUE;
971 else if (targ >= 0)
972 targ++;
973 else if (instance >= 0)
974 instance++;
975 opt_arg++;
976 break;
977 case '\0':
978 done = TRUE;
979 break;
980 default:
981 tok_end = end;
982 for (i = 0; tok_list[i]; i++) {
983 tok_end2 = strchr(opt_arg, tok_list[i]);
984 if ((tok_end2) && (tok_end2 < tok_end))
985 tok_end = tok_end2;
986 }
987 callback(callback_arg, instance, targ,
988 simple_strtol(opt_arg, NULL, 0));
989 opt_arg = tok_end;
990 break;
991 }
992 }
993 return (opt_arg);
994}
995
923/* 996/*
924 * Handle Linux boot parameters. This routine allows for assigning a value 997 * Handle Linux boot parameters. This routine allows for assigning a value
925 * to a parameter with a ':' between the parameter and the value. 998 * to a parameter with a ':' between the parameter and the value.
@@ -974,7 +1047,7 @@ aic7xxx_setup(char *s)
974 if (strncmp(p, "global_tag_depth", n) == 0) { 1047 if (strncmp(p, "global_tag_depth", n) == 0) {
975 ahc_linux_setup_tag_info_global(p + n); 1048 ahc_linux_setup_tag_info_global(p + n);
976 } else if (strncmp(p, "tag_info", n) == 0) { 1049 } else if (strncmp(p, "tag_info", n) == 0) {
977 s = aic_parse_brace_option("tag_info", p + n, end, 1050 s = ahc_parse_brace_option("tag_info", p + n, end,
978 2, ahc_linux_setup_tag_info, 0); 1051 2, ahc_linux_setup_tag_info, 0);
979 } else if (p[n] == ':') { 1052 } else if (p[n] == ':') {
980 *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); 1053 *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 3802c91f0b07..04a3506cf340 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -54,6 +54,49 @@ static void ahc_dump_device_state(struct info_str *info,
54static int ahc_proc_write_seeprom(struct ahc_softc *ahc, 54static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
55 char *buffer, int length); 55 char *buffer, int length);
56 56
57/*
58 * Table of syncrates that don't follow the "divisible by 4"
59 * rule. This table will be expanded in future SCSI specs.
60 */
61static struct {
62 u_int period_factor;
63 u_int period; /* in 100ths of ns */
64} scsi_syncrates[] = {
65 { 0x08, 625 }, /* FAST-160 */
66 { 0x09, 1250 }, /* FAST-80 */
67 { 0x0a, 2500 }, /* FAST-40 40MHz */
68 { 0x0b, 3030 }, /* FAST-40 33MHz */
69 { 0x0c, 5000 } /* FAST-20 */
70};
71
72/*
73 * Return the frequency in kHz corresponding to the given
74 * sync period factor.
75 */
76static u_int
77ahc_calc_syncsrate(u_int period_factor)
78{
79 int i;
80 int num_syncrates;
81
82 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
83 /* See if the period is in the "exception" table */
84 for (i = 0; i < num_syncrates; i++) {
85
86 if (period_factor == scsi_syncrates[i].period_factor) {
87 /* Period in kHz */
88 return (100000000 / scsi_syncrates[i].period);
89 }
90 }
91
92 /*
93 * Wasn't in the table, so use the standard
94 * 4 times conversion.
95 */
96 return (10000000 / (period_factor * 4 * 10));
97}
98
99
57static void 100static void
58copy_mem_info(struct info_str *info, char *data, int len) 101copy_mem_info(struct info_str *info, char *data, int len)
59{ 102{
@@ -106,7 +149,7 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
106 speed = 3300; 149 speed = 3300;
107 freq = 0; 150 freq = 0;
108 if (tinfo->offset != 0) { 151 if (tinfo->offset != 0) {
109 freq = aic_calc_syncsrate(tinfo->period); 152 freq = ahc_calc_syncsrate(tinfo->period);
110 speed = freq; 153 speed = freq;
111 } 154 }
112 speed *= (0x01 << tinfo->width); 155 speed *= (0x01 << tinfo->width);
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
index 4d44a9211185..828ae3d9a510 100644
--- a/drivers/scsi/aic7xxx/aiclib.c
+++ b/drivers/scsi/aic7xxx/aiclib.c
@@ -32,124 +32,3 @@
32 32
33#include "aiclib.h" 33#include "aiclib.h"
34 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 */
40static 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 */
55u_int
56aic_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
78char *
79aic_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}
diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
index e7d94cbaf2a8..3bfbf0fe1ec2 100644
--- a/drivers/scsi/aic7xxx/aiclib.h
+++ b/drivers/scsi/aic7xxx/aiclib.h
@@ -141,28 +141,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors)
141 return (int)capacity; 141 return (int)capacity;
142} 142}
143 143
144/**************************** Module Library Hack *****************************/
145/*
146 * What we'd like to do is have a single "scsi library" module that both the
147 * aic7xxx and aic79xx drivers could load and depend on. A cursory examination
148 * of implementing module dependencies in Linux (handling the install and
149 * initrd cases) does not look promissing. For now, we just duplicate this
150 * code in both drivers using a simple symbol renaming scheme that hides this
151 * hack from the drivers.
152 */
153#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x
154#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix)
155#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX)
156
157#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate)
158
159u_int aic_calc_syncsrate(u_int /*period_factor*/);
160
161typedef void aic_option_callback_t(u_long, int, int, int32_t);
162char * aic_parse_brace_option(char *opt_name, char *opt_arg,
163 char *end, int depth,
164 aic_option_callback_t *, u_long);
165
166static __inline uint32_t 144static __inline uint32_t
167scsi_4btoul(uint8_t *bytes) 145scsi_4btoul(uint8_t *bytes)
168{ 146{