diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/aic7xxx/aic79xx_proc.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/aic7xxx/aic79xx_proc.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_proc.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c new file mode 100644 index 000000000000..e01cd6175e34 --- /dev/null +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2001 Adaptec Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions, and the following disclaimer, | ||
10 | * without modification. | ||
11 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
12 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
13 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
14 | * including a substantially similar Disclaimer requirement for further | ||
15 | * binary redistribution. | ||
16 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
17 | * of any contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * NO WARRANTY | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
29 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
33 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
34 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
35 | * POSSIBILITY OF SUCH DAMAGES. | ||
36 | * | ||
37 | * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr> | ||
38 | * sym driver. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#19 $ | ||
41 | */ | ||
42 | #include "aic79xx_osm.h" | ||
43 | #include "aic79xx_inline.h" | ||
44 | |||
45 | static void copy_mem_info(struct info_str *info, char *data, int len); | ||
46 | static int copy_info(struct info_str *info, char *fmt, ...); | ||
47 | static void ahd_dump_target_state(struct ahd_softc *ahd, | ||
48 | struct info_str *info, | ||
49 | u_int our_id, char channel, | ||
50 | u_int target_id, u_int target_offset); | ||
51 | static void ahd_dump_device_state(struct info_str *info, | ||
52 | struct ahd_linux_device *dev); | ||
53 | static int ahd_proc_write_seeprom(struct ahd_softc *ahd, | ||
54 | char *buffer, int length); | ||
55 | |||
56 | static void | ||
57 | copy_mem_info(struct info_str *info, char *data, int len) | ||
58 | { | ||
59 | if (info->pos + len > info->offset + info->length) | ||
60 | len = info->offset + info->length - info->pos; | ||
61 | |||
62 | if (info->pos + len < info->offset) { | ||
63 | info->pos += len; | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | if (info->pos < info->offset) { | ||
68 | off_t partial; | ||
69 | |||
70 | partial = info->offset - info->pos; | ||
71 | data += partial; | ||
72 | info->pos += partial; | ||
73 | len -= partial; | ||
74 | } | ||
75 | |||
76 | if (len > 0) { | ||
77 | memcpy(info->buffer, data, len); | ||
78 | info->pos += len; | ||
79 | info->buffer += len; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static int | ||
84 | copy_info(struct info_str *info, char *fmt, ...) | ||
85 | { | ||
86 | va_list args; | ||
87 | char buf[256]; | ||
88 | int len; | ||
89 | |||
90 | va_start(args, fmt); | ||
91 | len = vsprintf(buf, fmt, args); | ||
92 | va_end(args); | ||
93 | |||
94 | copy_mem_info(info, buf, len); | ||
95 | return (len); | ||
96 | } | ||
97 | |||
98 | void | ||
99 | ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) | ||
100 | { | ||
101 | u_int speed; | ||
102 | u_int freq; | ||
103 | u_int mb; | ||
104 | |||
105 | if (tinfo->period == AHD_PERIOD_UNKNOWN) { | ||
106 | copy_info(info, "Renegotiation Pending\n"); | ||
107 | return; | ||
108 | } | ||
109 | speed = 3300; | ||
110 | freq = 0; | ||
111 | if (tinfo->offset != 0) { | ||
112 | freq = aic_calc_syncsrate(tinfo->period); | ||
113 | speed = freq; | ||
114 | } | ||
115 | speed *= (0x01 << tinfo->width); | ||
116 | mb = speed / 1000; | ||
117 | if (mb > 0) | ||
118 | copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000); | ||
119 | else | ||
120 | copy_info(info, "%dKB/s transfers", speed); | ||
121 | |||
122 | if (freq != 0) { | ||
123 | int printed_options; | ||
124 | |||
125 | printed_options = 0; | ||
126 | copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000); | ||
127 | if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { | ||
128 | copy_info(info, " RDSTRM"); | ||
129 | printed_options++; | ||
130 | } | ||
131 | if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { | ||
132 | copy_info(info, "%s", printed_options ? "|DT" : " DT"); | ||
133 | printed_options++; | ||
134 | } | ||
135 | if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { | ||
136 | copy_info(info, "%s", printed_options ? "|IU" : " IU"); | ||
137 | printed_options++; | ||
138 | } | ||
139 | if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) { | ||
140 | copy_info(info, "%s", | ||
141 | printed_options ? "|RTI" : " RTI"); | ||
142 | printed_options++; | ||
143 | } | ||
144 | if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { | ||
145 | copy_info(info, "%s", | ||
146 | printed_options ? "|QAS" : " QAS"); | ||
147 | printed_options++; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (tinfo->width > 0) { | ||
152 | if (freq != 0) { | ||
153 | copy_info(info, ", "); | ||
154 | } else { | ||
155 | copy_info(info, " ("); | ||
156 | } | ||
157 | copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width)); | ||
158 | } else if (freq != 0) { | ||
159 | copy_info(info, ")"); | ||
160 | } | ||
161 | copy_info(info, "\n"); | ||
162 | } | ||
163 | |||
164 | static void | ||
165 | ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, | ||
166 | u_int our_id, char channel, u_int target_id, | ||
167 | u_int target_offset) | ||
168 | { | ||
169 | struct ahd_linux_target *targ; | ||
170 | struct ahd_initiator_tinfo *tinfo; | ||
171 | struct ahd_tmode_tstate *tstate; | ||
172 | int lun; | ||
173 | |||
174 | tinfo = ahd_fetch_transinfo(ahd, channel, our_id, | ||
175 | target_id, &tstate); | ||
176 | copy_info(info, "Target %d Negotiation Settings\n", target_id); | ||
177 | copy_info(info, "\tUser: "); | ||
178 | ahd_format_transinfo(info, &tinfo->user); | ||
179 | targ = ahd->platform_data->targets[target_offset]; | ||
180 | if (targ == NULL) | ||
181 | return; | ||
182 | |||
183 | copy_info(info, "\tGoal: "); | ||
184 | ahd_format_transinfo(info, &tinfo->goal); | ||
185 | copy_info(info, "\tCurr: "); | ||
186 | ahd_format_transinfo(info, &tinfo->curr); | ||
187 | copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected); | ||
188 | |||
189 | for (lun = 0; lun < AHD_NUM_LUNS; lun++) { | ||
190 | struct ahd_linux_device *dev; | ||
191 | |||
192 | dev = targ->devices[lun]; | ||
193 | |||
194 | if (dev == NULL) | ||
195 | continue; | ||
196 | |||
197 | ahd_dump_device_state(info, dev); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev) | ||
203 | { | ||
204 | copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", | ||
205 | dev->target->channel + 'A', dev->target->target, dev->lun); | ||
206 | |||
207 | copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); | ||
208 | copy_info(info, "\t\tCommands Active %d\n", dev->active); | ||
209 | copy_info(info, "\t\tCommand Openings %d\n", dev->openings); | ||
210 | copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); | ||
211 | copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); | ||
212 | } | ||
213 | |||
214 | static int | ||
215 | ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) | ||
216 | { | ||
217 | ahd_mode_state saved_modes; | ||
218 | int have_seeprom; | ||
219 | u_long s; | ||
220 | int paused; | ||
221 | int written; | ||
222 | |||
223 | /* Default to failure. */ | ||
224 | written = -EINVAL; | ||
225 | ahd_lock(ahd, &s); | ||
226 | paused = ahd_is_paused(ahd); | ||
227 | if (!paused) | ||
228 | ahd_pause(ahd); | ||
229 | |||
230 | saved_modes = ahd_save_modes(ahd); | ||
231 | ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); | ||
232 | if (length != sizeof(struct seeprom_config)) { | ||
233 | printf("ahd_proc_write_seeprom: incorrect buffer size\n"); | ||
234 | goto done; | ||
235 | } | ||
236 | |||
237 | have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer); | ||
238 | if (have_seeprom == 0) { | ||
239 | printf("ahd_proc_write_seeprom: cksum verification failed\n"); | ||
240 | goto done; | ||
241 | } | ||
242 | |||
243 | have_seeprom = ahd_acquire_seeprom(ahd); | ||
244 | if (!have_seeprom) { | ||
245 | printf("ahd_proc_write_seeprom: No Serial EEPROM\n"); | ||
246 | goto done; | ||
247 | } else { | ||
248 | u_int start_addr; | ||
249 | |||
250 | if (ahd->seep_config == NULL) { | ||
251 | ahd->seep_config = malloc(sizeof(*ahd->seep_config), | ||
252 | M_DEVBUF, M_NOWAIT); | ||
253 | if (ahd->seep_config == NULL) { | ||
254 | printf("aic79xx: Unable to allocate serial " | ||
255 | "eeprom buffer. Write failing\n"); | ||
256 | goto done; | ||
257 | } | ||
258 | } | ||
259 | printf("aic79xx: Writing Serial EEPROM\n"); | ||
260 | start_addr = 32 * (ahd->channel - 'A'); | ||
261 | ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr, | ||
262 | sizeof(struct seeprom_config)/2); | ||
263 | ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config, | ||
264 | start_addr, sizeof(struct seeprom_config)/2, | ||
265 | /*ByteStream*/FALSE); | ||
266 | ahd_release_seeprom(ahd); | ||
267 | written = length; | ||
268 | } | ||
269 | |||
270 | done: | ||
271 | ahd_restore_modes(ahd, saved_modes); | ||
272 | if (!paused) | ||
273 | ahd_unpause(ahd); | ||
274 | ahd_unlock(ahd, &s); | ||
275 | return (written); | ||
276 | } | ||
277 | /* | ||
278 | * Return information to handle /proc support for the driver. | ||
279 | */ | ||
280 | int | ||
281 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | ||
282 | ahd_linux_proc_info(char *buffer, char **start, off_t offset, | ||
283 | int length, int hostno, int inout) | ||
284 | #else | ||
285 | ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, | ||
286 | off_t offset, int length, int inout) | ||
287 | #endif | ||
288 | { | ||
289 | struct ahd_softc *ahd; | ||
290 | struct info_str info; | ||
291 | char ahd_info[256]; | ||
292 | u_long l; | ||
293 | u_int max_targ; | ||
294 | u_int i; | ||
295 | int retval; | ||
296 | |||
297 | retval = -EINVAL; | ||
298 | ahd_list_lock(&l); | ||
299 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | ||
300 | TAILQ_FOREACH(ahd, &ahd_tailq, links) { | ||
301 | if (ahd->platform_data->host->host_no == hostno) | ||
302 | break; | ||
303 | } | ||
304 | #else | ||
305 | ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); | ||
306 | #endif | ||
307 | |||
308 | if (ahd == NULL) | ||
309 | goto done; | ||
310 | |||
311 | /* Has data been written to the file? */ | ||
312 | if (inout == TRUE) { | ||
313 | retval = ahd_proc_write_seeprom(ahd, buffer, length); | ||
314 | goto done; | ||
315 | } | ||
316 | |||
317 | if (start) | ||
318 | *start = buffer; | ||
319 | |||
320 | info.buffer = buffer; | ||
321 | info.length = length; | ||
322 | info.offset = offset; | ||
323 | info.pos = 0; | ||
324 | |||
325 | copy_info(&info, "Adaptec AIC79xx driver version: %s\n", | ||
326 | AIC79XX_DRIVER_VERSION); | ||
327 | copy_info(&info, "%s\n", ahd->description); | ||
328 | ahd_controller_info(ahd, ahd_info); | ||
329 | copy_info(&info, "%s\n", ahd_info); | ||
330 | copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", | ||
331 | ahd->scb_data.numscbs, AHD_NSEG); | ||
332 | |||
333 | max_targ = 15; | ||
334 | |||
335 | if (ahd->seep_config == NULL) | ||
336 | copy_info(&info, "No Serial EEPROM\n"); | ||
337 | else { | ||
338 | copy_info(&info, "Serial EEPROM:\n"); | ||
339 | for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) { | ||
340 | if (((i % 8) == 0) && (i != 0)) { | ||
341 | copy_info(&info, "\n"); | ||
342 | } | ||
343 | copy_info(&info, "0x%.4x ", | ||
344 | ((uint16_t*)ahd->seep_config)[i]); | ||
345 | } | ||
346 | copy_info(&info, "\n"); | ||
347 | } | ||
348 | copy_info(&info, "\n"); | ||
349 | |||
350 | if ((ahd->features & AHD_WIDE) == 0) | ||
351 | max_targ = 7; | ||
352 | |||
353 | for (i = 0; i <= max_targ; i++) { | ||
354 | |||
355 | ahd_dump_target_state(ahd, &info, ahd->our_id, 'A', | ||
356 | /*target_id*/i, /*target_offset*/i); | ||
357 | } | ||
358 | retval = info.pos > info.offset ? info.pos - info.offset : 0; | ||
359 | done: | ||
360 | ahd_list_unlock(&l); | ||
361 | return (retval); | ||
362 | } | ||