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/wd33c93.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/wd33c93.c')
-rw-r--r-- | drivers/scsi/wd33c93.c | 2077 |
1 files changed, 2077 insertions, 0 deletions
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c new file mode 100644 index 000000000000..5754445fb36a --- /dev/null +++ b/drivers/scsi/wd33c93.c | |||
@@ -0,0 +1,2077 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1996 John Shifflett, GeoLog Consulting | ||
3 | * john@geolog.com | ||
4 | * jshiffle@netcom.com | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC | ||
19 | * provided much of the inspiration and some of the code for this | ||
20 | * driver. Everything I know about Amiga DMA was gleaned from careful | ||
21 | * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I | ||
22 | * borrowed shamelessly from all over that source. Thanks Hamish! | ||
23 | * | ||
24 | * _This_ driver is (I feel) an improvement over the old one in | ||
25 | * several respects: | ||
26 | * | ||
27 | * - Target Disconnection/Reconnection is now supported. Any | ||
28 | * system with more than one device active on the SCSI bus | ||
29 | * will benefit from this. The driver defaults to what I | ||
30 | * call 'adaptive disconnect' - meaning that each command | ||
31 | * is evaluated individually as to whether or not it should | ||
32 | * be run with the option to disconnect/reselect (if the | ||
33 | * device chooses), or as a "SCSI-bus-hog". | ||
34 | * | ||
35 | * - Synchronous data transfers are now supported. Because of | ||
36 | * a few devices that choke after telling the driver that | ||
37 | * they can do sync transfers, we don't automatically use | ||
38 | * this faster protocol - it can be enabled via the command- | ||
39 | * line on a device-by-device basis. | ||
40 | * | ||
41 | * - Runtime operating parameters can now be specified through | ||
42 | * the 'amiboot' or the 'insmod' command line. For amiboot do: | ||
43 | * "amiboot [usual stuff] wd33c93=blah,blah,blah" | ||
44 | * The defaults should be good for most people. See the comment | ||
45 | * for 'setup_strings' below for more details. | ||
46 | * | ||
47 | * - The old driver relied exclusively on what the Western Digital | ||
48 | * docs call "Combination Level 2 Commands", which are a great | ||
49 | * idea in that the CPU is relieved of a lot of interrupt | ||
50 | * overhead. However, by accepting a certain (user-settable) | ||
51 | * amount of additional interrupts, this driver achieves | ||
52 | * better control over the SCSI bus, and data transfers are | ||
53 | * almost as fast while being much easier to define, track, | ||
54 | * and debug. | ||
55 | * | ||
56 | * | ||
57 | * TODO: | ||
58 | * more speed. linked commands. | ||
59 | * | ||
60 | * | ||
61 | * People with bug reports, wish-lists, complaints, comments, | ||
62 | * or improvements are asked to pah-leeez email me (John Shifflett) | ||
63 | * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get | ||
64 | * this thing into as good a shape as possible, and I'm positive | ||
65 | * there are lots of lurking bugs and "Stupid Places". | ||
66 | * | ||
67 | * Updates: | ||
68 | * | ||
69 | * Added support for pre -A chips, which don't have advanced features | ||
70 | * and will generate CSR_RESEL rather than CSR_RESEL_AM. | ||
71 | * Richard Hirst <richard@sleepie.demon.co.uk> August 2000 | ||
72 | */ | ||
73 | |||
74 | #include <linux/config.h> | ||
75 | #include <linux/module.h> | ||
76 | |||
77 | #include <linux/sched.h> | ||
78 | #include <linux/string.h> | ||
79 | #include <linux/delay.h> | ||
80 | #include <linux/version.h> | ||
81 | #include <linux/init.h> | ||
82 | #include <linux/blkdev.h> | ||
83 | #include <asm/irq.h> | ||
84 | |||
85 | #include <scsi/scsi.h> | ||
86 | #include <scsi/scsi_cmnd.h> | ||
87 | #include <scsi/scsi_device.h> | ||
88 | #include <scsi/scsi_host.h> | ||
89 | |||
90 | #include "wd33c93.h" | ||
91 | |||
92 | |||
93 | #define WD33C93_VERSION "1.26" | ||
94 | #define WD33C93_DATE "22/Feb/2003" | ||
95 | |||
96 | MODULE_AUTHOR("John Shifflett"); | ||
97 | MODULE_DESCRIPTION("Generic WD33C93 SCSI driver"); | ||
98 | MODULE_LICENSE("GPL"); | ||
99 | |||
100 | /* | ||
101 | * 'setup_strings' is a single string used to pass operating parameters and | ||
102 | * settings from the kernel/module command-line to the driver. 'setup_args[]' | ||
103 | * is an array of strings that define the compile-time default values for | ||
104 | * these settings. If Linux boots with an amiboot or insmod command-line, | ||
105 | * those settings are combined with 'setup_args[]'. Note that amiboot | ||
106 | * command-lines are prefixed with "wd33c93=" while insmod uses a | ||
107 | * "setup_strings=" prefix. The driver recognizes the following keywords | ||
108 | * (lower case required) and arguments: | ||
109 | * | ||
110 | * - nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with | ||
111 | * the 7 possible SCSI devices. Set a bit to negotiate for | ||
112 | * asynchronous transfers on that device. To maintain | ||
113 | * backwards compatibility, a command-line such as | ||
114 | * "wd33c93=255" will be automatically translated to | ||
115 | * "wd33c93=nosync:0xff". | ||
116 | * - nodma:x -x = 1 to disable DMA, x = 0 to enable it. Argument is | ||
117 | * optional - if not present, same as "nodma:1". | ||
118 | * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer | ||
119 | * period. Default is 500; acceptable values are 250 - 1000. | ||
120 | * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them. | ||
121 | * x = 1 does 'adaptive' disconnects, which is the default | ||
122 | * and generally the best choice. | ||
123 | * - debug:x -If 'DEBUGGING_ON' is defined, x is a bit mask that causes | ||
124 | * various types of debug output to printed - see the DB_xxx | ||
125 | * defines in wd33c93.h | ||
126 | * - clock:x -x = clock input in MHz for WD33c93 chip. Normal values | ||
127 | * would be from 8 through 20. Default is 8. | ||
128 | * - next -No argument. Used to separate blocks of keywords when | ||
129 | * there's more than one host adapter in the system. | ||
130 | * | ||
131 | * Syntax Notes: | ||
132 | * - Numeric arguments can be decimal or the '0x' form of hex notation. There | ||
133 | * _must_ be a colon between a keyword and its numeric argument, with no | ||
134 | * spaces. | ||
135 | * - Keywords are separated by commas, no spaces, in the standard kernel | ||
136 | * command-line manner. | ||
137 | * - A keyword in the 'nth' comma-separated command-line member will overwrite | ||
138 | * the 'nth' element of setup_args[]. A blank command-line member (in | ||
139 | * other words, a comma with no preceding keyword) will _not_ overwrite | ||
140 | * the corresponding setup_args[] element. | ||
141 | * - If a keyword is used more than once, the first one applies to the first | ||
142 | * SCSI host found, the second to the second card, etc, unless the 'next' | ||
143 | * keyword is used to change the order. | ||
144 | * | ||
145 | * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'): | ||
146 | * - wd33c93=nosync:255 | ||
147 | * - wd33c93=nodma | ||
148 | * - wd33c93=nodma:1 | ||
149 | * - wd33c93=disconnect:2,nosync:0x08,period:250 | ||
150 | * - wd33c93=debug:0x1c | ||
151 | */ | ||
152 | |||
153 | /* Normally, no defaults are specified */ | ||
154 | static char *setup_args[] = { "", "", "", "", "", "", "", "", "" }; | ||
155 | |||
156 | static char *setup_strings; | ||
157 | module_param(setup_strings, charp, 0); | ||
158 | |||
159 | static void wd33c93_execute(struct Scsi_Host *instance); | ||
160 | |||
161 | #ifdef CONFIG_WD33C93_PIO | ||
162 | static inline uchar | ||
163 | read_wd33c93(const wd33c93_regs regs, uchar reg_num) | ||
164 | { | ||
165 | uchar data; | ||
166 | |||
167 | outb(reg_num, regs.SASR); | ||
168 | data = inb(regs.SCMD); | ||
169 | return data; | ||
170 | } | ||
171 | |||
172 | static inline unsigned long | ||
173 | read_wd33c93_count(const wd33c93_regs regs) | ||
174 | { | ||
175 | unsigned long value; | ||
176 | |||
177 | outb(WD_TRANSFER_COUNT_MSB, regs.SASR); | ||
178 | value = inb(regs.SCMD) << 16; | ||
179 | value |= inb(regs.SCMD) << 8; | ||
180 | value |= inb(regs.SCMD); | ||
181 | return value; | ||
182 | } | ||
183 | |||
184 | static inline uchar | ||
185 | read_aux_stat(const wd33c93_regs regs) | ||
186 | { | ||
187 | return inb(regs.SASR); | ||
188 | } | ||
189 | |||
190 | static inline void | ||
191 | write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value) | ||
192 | { | ||
193 | outb(reg_num, regs.SASR); | ||
194 | outb(value, regs.SCMD); | ||
195 | } | ||
196 | |||
197 | static inline void | ||
198 | write_wd33c93_count(const wd33c93_regs regs, unsigned long value) | ||
199 | { | ||
200 | outb(WD_TRANSFER_COUNT_MSB, regs.SASR); | ||
201 | outb((value >> 16) & 0xff, regs.SCMD); | ||
202 | outb((value >> 8) & 0xff, regs.SCMD); | ||
203 | outb( value & 0xff, regs.SCMD); | ||
204 | } | ||
205 | |||
206 | #define write_wd33c93_cmd(regs, cmd) \ | ||
207 | write_wd33c93((regs), WD_COMMAND, (cmd)) | ||
208 | |||
209 | static inline void | ||
210 | write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[]) | ||
211 | { | ||
212 | int i; | ||
213 | |||
214 | outb(WD_CDB_1, regs.SASR); | ||
215 | for (i=0; i<len; i++) | ||
216 | outb(cmnd[i], regs.SCMD); | ||
217 | } | ||
218 | |||
219 | #else /* CONFIG_WD33C93_PIO */ | ||
220 | static inline uchar | ||
221 | read_wd33c93(const wd33c93_regs regs, uchar reg_num) | ||
222 | { | ||
223 | *regs.SASR = reg_num; | ||
224 | mb(); | ||
225 | return (*regs.SCMD); | ||
226 | } | ||
227 | |||
228 | static unsigned long | ||
229 | read_wd33c93_count(const wd33c93_regs regs) | ||
230 | { | ||
231 | unsigned long value; | ||
232 | |||
233 | *regs.SASR = WD_TRANSFER_COUNT_MSB; | ||
234 | mb(); | ||
235 | value = *regs.SCMD << 16; | ||
236 | value |= *regs.SCMD << 8; | ||
237 | value |= *regs.SCMD; | ||
238 | mb(); | ||
239 | return value; | ||
240 | } | ||
241 | |||
242 | static inline uchar | ||
243 | read_aux_stat(const wd33c93_regs regs) | ||
244 | { | ||
245 | return *regs.SASR; | ||
246 | } | ||
247 | |||
248 | static inline void | ||
249 | write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value) | ||
250 | { | ||
251 | *regs.SASR = reg_num; | ||
252 | mb(); | ||
253 | *regs.SCMD = value; | ||
254 | mb(); | ||
255 | } | ||
256 | |||
257 | static void | ||
258 | write_wd33c93_count(const wd33c93_regs regs, unsigned long value) | ||
259 | { | ||
260 | *regs.SASR = WD_TRANSFER_COUNT_MSB; | ||
261 | mb(); | ||
262 | *regs.SCMD = value >> 16; | ||
263 | *regs.SCMD = value >> 8; | ||
264 | *regs.SCMD = value; | ||
265 | mb(); | ||
266 | } | ||
267 | |||
268 | static inline void | ||
269 | write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd) | ||
270 | { | ||
271 | *regs.SASR = WD_COMMAND; | ||
272 | mb(); | ||
273 | *regs.SCMD = cmd; | ||
274 | mb(); | ||
275 | } | ||
276 | |||
277 | static inline void | ||
278 | write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[]) | ||
279 | { | ||
280 | int i; | ||
281 | |||
282 | *regs.SASR = WD_CDB_1; | ||
283 | for (i = 0; i < len; i++) | ||
284 | *regs.SCMD = cmnd[i]; | ||
285 | } | ||
286 | #endif /* CONFIG_WD33C93_PIO */ | ||
287 | |||
288 | static inline uchar | ||
289 | read_1_byte(const wd33c93_regs regs) | ||
290 | { | ||
291 | uchar asr; | ||
292 | uchar x = 0; | ||
293 | |||
294 | write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); | ||
295 | write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO | 0x80); | ||
296 | do { | ||
297 | asr = read_aux_stat(regs); | ||
298 | if (asr & ASR_DBR) | ||
299 | x = read_wd33c93(regs, WD_DATA); | ||
300 | } while (!(asr & ASR_INT)); | ||
301 | return x; | ||
302 | } | ||
303 | |||
304 | static struct sx_period sx_table[] = { | ||
305 | {1, 0x20}, | ||
306 | {252, 0x20}, | ||
307 | {376, 0x30}, | ||
308 | {500, 0x40}, | ||
309 | {624, 0x50}, | ||
310 | {752, 0x60}, | ||
311 | {876, 0x70}, | ||
312 | {1000, 0x00}, | ||
313 | {0, 0} | ||
314 | }; | ||
315 | |||
316 | static int | ||
317 | round_period(unsigned int period) | ||
318 | { | ||
319 | int x; | ||
320 | |||
321 | for (x = 1; sx_table[x].period_ns; x++) { | ||
322 | if ((period <= sx_table[x - 0].period_ns) && | ||
323 | (period > sx_table[x - 1].period_ns)) { | ||
324 | return x; | ||
325 | } | ||
326 | } | ||
327 | return 7; | ||
328 | } | ||
329 | |||
330 | static uchar | ||
331 | calc_sync_xfer(unsigned int period, unsigned int offset) | ||
332 | { | ||
333 | uchar result; | ||
334 | |||
335 | period *= 4; /* convert SDTR code to ns */ | ||
336 | result = sx_table[round_period(period)].reg_value; | ||
337 | result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; | ||
338 | return result; | ||
339 | } | ||
340 | |||
341 | int | ||
342 | wd33c93_queuecommand(struct scsi_cmnd *cmd, | ||
343 | void (*done)(struct scsi_cmnd *)) | ||
344 | { | ||
345 | struct WD33C93_hostdata *hostdata; | ||
346 | struct scsi_cmnd *tmp; | ||
347 | |||
348 | hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; | ||
349 | |||
350 | DB(DB_QUEUE_COMMAND, | ||
351 | printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid)) | ||
352 | |||
353 | /* Set up a few fields in the scsi_cmnd structure for our own use: | ||
354 | * - host_scribble is the pointer to the next cmd in the input queue | ||
355 | * - scsi_done points to the routine we call when a cmd is finished | ||
356 | * - result is what you'd expect | ||
357 | */ | ||
358 | cmd->host_scribble = NULL; | ||
359 | cmd->scsi_done = done; | ||
360 | cmd->result = 0; | ||
361 | |||
362 | /* We use the Scsi_Pointer structure that's included with each command | ||
363 | * as a scratchpad (as it's intended to be used!). The handy thing about | ||
364 | * the SCp.xxx fields is that they're always associated with a given | ||
365 | * cmd, and are preserved across disconnect-reselect. This means we | ||
366 | * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages | ||
367 | * if we keep all the critical pointers and counters in SCp: | ||
368 | * - SCp.ptr is the pointer into the RAM buffer | ||
369 | * - SCp.this_residual is the size of that buffer | ||
370 | * - SCp.buffer points to the current scatter-gather buffer | ||
371 | * - SCp.buffers_residual tells us how many S.G. buffers there are | ||
372 | * - SCp.have_data_in is not used | ||
373 | * - SCp.sent_command is not used | ||
374 | * - SCp.phase records this command's SRCID_ER bit setting | ||
375 | */ | ||
376 | |||
377 | if (cmd->use_sg) { | ||
378 | cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; | ||
379 | cmd->SCp.buffers_residual = cmd->use_sg - 1; | ||
380 | cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + | ||
381 | cmd->SCp.buffer->offset; | ||
382 | cmd->SCp.this_residual = cmd->SCp.buffer->length; | ||
383 | } else { | ||
384 | cmd->SCp.buffer = NULL; | ||
385 | cmd->SCp.buffers_residual = 0; | ||
386 | cmd->SCp.ptr = (char *) cmd->request_buffer; | ||
387 | cmd->SCp.this_residual = cmd->request_bufflen; | ||
388 | } | ||
389 | |||
390 | /* WD docs state that at the conclusion of a "LEVEL2" command, the | ||
391 | * status byte can be retrieved from the LUN register. Apparently, | ||
392 | * this is the case only for *uninterrupted* LEVEL2 commands! If | ||
393 | * there are any unexpected phases entered, even if they are 100% | ||
394 | * legal (different devices may choose to do things differently), | ||
395 | * the LEVEL2 command sequence is exited. This often occurs prior | ||
396 | * to receiving the status byte, in which case the driver does a | ||
397 | * status phase interrupt and gets the status byte on its own. | ||
398 | * While such a command can then be "resumed" (ie restarted to | ||
399 | * finish up as a LEVEL2 command), the LUN register will NOT be | ||
400 | * a valid status byte at the command's conclusion, and we must | ||
401 | * use the byte obtained during the earlier interrupt. Here, we | ||
402 | * preset SCp.Status to an illegal value (0xff) so that when | ||
403 | * this command finally completes, we can tell where the actual | ||
404 | * status byte is stored. | ||
405 | */ | ||
406 | |||
407 | cmd->SCp.Status = ILLEGAL_STATUS_BYTE; | ||
408 | |||
409 | /* | ||
410 | * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE | ||
411 | * commands are added to the head of the queue so that the desired | ||
412 | * sense data is not lost before REQUEST_SENSE executes. | ||
413 | */ | ||
414 | |||
415 | spin_lock_irq(&hostdata->lock); | ||
416 | |||
417 | if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { | ||
418 | cmd->host_scribble = (uchar *) hostdata->input_Q; | ||
419 | hostdata->input_Q = cmd; | ||
420 | } else { /* find the end of the queue */ | ||
421 | for (tmp = (struct scsi_cmnd *) hostdata->input_Q; | ||
422 | tmp->host_scribble; | ||
423 | tmp = (struct scsi_cmnd *) tmp->host_scribble) ; | ||
424 | tmp->host_scribble = (uchar *) cmd; | ||
425 | } | ||
426 | |||
427 | /* We know that there's at least one command in 'input_Q' now. | ||
428 | * Go see if any of them are runnable! | ||
429 | */ | ||
430 | |||
431 | wd33c93_execute(cmd->device->host); | ||
432 | |||
433 | DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid)) | ||
434 | |||
435 | spin_unlock_irq(&hostdata->lock); | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * This routine attempts to start a scsi command. If the host_card is | ||
441 | * already connected, we give up immediately. Otherwise, look through | ||
442 | * the input_Q, using the first command we find that's intended | ||
443 | * for a currently non-busy target/lun. | ||
444 | * | ||
445 | * wd33c93_execute() is always called with interrupts disabled or from | ||
446 | * the wd33c93_intr itself, which means that a wd33c93 interrupt | ||
447 | * cannot occur while we are in here. | ||
448 | */ | ||
449 | static void | ||
450 | wd33c93_execute(struct Scsi_Host *instance) | ||
451 | { | ||
452 | struct WD33C93_hostdata *hostdata = | ||
453 | (struct WD33C93_hostdata *) instance->hostdata; | ||
454 | const wd33c93_regs regs = hostdata->regs; | ||
455 | struct scsi_cmnd *cmd, *prev; | ||
456 | |||
457 | DB(DB_EXECUTE, printk("EX(")) | ||
458 | if (hostdata->selecting || hostdata->connected) { | ||
459 | DB(DB_EXECUTE, printk(")EX-0 ")) | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * Search through the input_Q for a command destined | ||
465 | * for an idle target/lun. | ||
466 | */ | ||
467 | |||
468 | cmd = (struct scsi_cmnd *) hostdata->input_Q; | ||
469 | prev = 0; | ||
470 | while (cmd) { | ||
471 | if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))) | ||
472 | break; | ||
473 | prev = cmd; | ||
474 | cmd = (struct scsi_cmnd *) cmd->host_scribble; | ||
475 | } | ||
476 | |||
477 | /* quit if queue empty or all possible targets are busy */ | ||
478 | |||
479 | if (!cmd) { | ||
480 | DB(DB_EXECUTE, printk(")EX-1 ")) | ||
481 | return; | ||
482 | } | ||
483 | |||
484 | /* remove command from queue */ | ||
485 | |||
486 | if (prev) | ||
487 | prev->host_scribble = cmd->host_scribble; | ||
488 | else | ||
489 | hostdata->input_Q = (struct scsi_cmnd *) cmd->host_scribble; | ||
490 | |||
491 | #ifdef PROC_STATISTICS | ||
492 | hostdata->cmd_cnt[cmd->device->id]++; | ||
493 | #endif | ||
494 | |||
495 | /* | ||
496 | * Start the selection process | ||
497 | */ | ||
498 | |||
499 | if (cmd->sc_data_direction == DMA_TO_DEVICE) | ||
500 | write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id); | ||
501 | else | ||
502 | write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD); | ||
503 | |||
504 | /* Now we need to figure out whether or not this command is a good | ||
505 | * candidate for disconnect/reselect. We guess to the best of our | ||
506 | * ability, based on a set of hierarchical rules. When several | ||
507 | * devices are operating simultaneously, disconnects are usually | ||
508 | * an advantage. In a single device system, or if only 1 device | ||
509 | * is being accessed, transfers usually go faster if disconnects | ||
510 | * are not allowed: | ||
511 | * | ||
512 | * + Commands should NEVER disconnect if hostdata->disconnect = | ||
513 | * DIS_NEVER (this holds for tape drives also), and ALWAYS | ||
514 | * disconnect if hostdata->disconnect = DIS_ALWAYS. | ||
515 | * + Tape drive commands should always be allowed to disconnect. | ||
516 | * + Disconnect should be allowed if disconnected_Q isn't empty. | ||
517 | * + Commands should NOT disconnect if input_Q is empty. | ||
518 | * + Disconnect should be allowed if there are commands in input_Q | ||
519 | * for a different target/lun. In this case, the other commands | ||
520 | * should be made disconnect-able, if not already. | ||
521 | * | ||
522 | * I know, I know - this code would flunk me out of any | ||
523 | * "C Programming 101" class ever offered. But it's easy | ||
524 | * to change around and experiment with for now. | ||
525 | */ | ||
526 | |||
527 | cmd->SCp.phase = 0; /* assume no disconnect */ | ||
528 | if (hostdata->disconnect == DIS_NEVER) | ||
529 | goto no; | ||
530 | if (hostdata->disconnect == DIS_ALWAYS) | ||
531 | goto yes; | ||
532 | if (cmd->device->type == 1) /* tape drive? */ | ||
533 | goto yes; | ||
534 | if (hostdata->disconnected_Q) /* other commands disconnected? */ | ||
535 | goto yes; | ||
536 | if (!(hostdata->input_Q)) /* input_Q empty? */ | ||
537 | goto no; | ||
538 | for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev; | ||
539 | prev = (struct scsi_cmnd *) prev->host_scribble) { | ||
540 | if ((prev->device->id != cmd->device->id) || | ||
541 | (prev->device->lun != cmd->device->lun)) { | ||
542 | for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev; | ||
543 | prev = (struct scsi_cmnd *) prev->host_scribble) | ||
544 | prev->SCp.phase = 1; | ||
545 | goto yes; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | goto no; | ||
550 | |||
551 | yes: | ||
552 | cmd->SCp.phase = 1; | ||
553 | |||
554 | #ifdef PROC_STATISTICS | ||
555 | hostdata->disc_allowed_cnt[cmd->device->id]++; | ||
556 | #endif | ||
557 | |||
558 | no: | ||
559 | |||
560 | write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0)); | ||
561 | |||
562 | write_wd33c93(regs, WD_TARGET_LUN, cmd->device->lun); | ||
563 | write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, | ||
564 | hostdata->sync_xfer[cmd->device->id]); | ||
565 | hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); | ||
566 | |||
567 | if ((hostdata->level2 == L2_NONE) || | ||
568 | (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) { | ||
569 | |||
570 | /* | ||
571 | * Do a 'Select-With-ATN' command. This will end with | ||
572 | * one of the following interrupts: | ||
573 | * CSR_RESEL_AM: failure - can try again later. | ||
574 | * CSR_TIMEOUT: failure - give up. | ||
575 | * CSR_SELECT: success - proceed. | ||
576 | */ | ||
577 | |||
578 | hostdata->selecting = cmd; | ||
579 | |||
580 | /* Every target has its own synchronous transfer setting, kept in the | ||
581 | * sync_xfer array, and a corresponding status byte in sync_stat[]. | ||
582 | * Each target's sync_stat[] entry is initialized to SX_UNSET, and its | ||
583 | * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET | ||
584 | * means that the parameters are undetermined as yet, and that we | ||
585 | * need to send an SDTR message to this device after selection is | ||
586 | * complete: We set SS_FIRST to tell the interrupt routine to do so. | ||
587 | * If we've been asked not to try synchronous transfers on this | ||
588 | * target (and _all_ luns within it), we'll still send the SDTR message | ||
589 | * later, but at that time we'll negotiate for async by specifying a | ||
590 | * sync fifo depth of 0. | ||
591 | */ | ||
592 | if (hostdata->sync_stat[cmd->device->id] == SS_UNSET) | ||
593 | hostdata->sync_stat[cmd->device->id] = SS_FIRST; | ||
594 | hostdata->state = S_SELECTING; | ||
595 | write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ | ||
596 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN); | ||
597 | } else { | ||
598 | |||
599 | /* | ||
600 | * Do a 'Select-With-ATN-Xfer' command. This will end with | ||
601 | * one of the following interrupts: | ||
602 | * CSR_RESEL_AM: failure - can try again later. | ||
603 | * CSR_TIMEOUT: failure - give up. | ||
604 | * anything else: success - proceed. | ||
605 | */ | ||
606 | |||
607 | hostdata->connected = cmd; | ||
608 | write_wd33c93(regs, WD_COMMAND_PHASE, 0); | ||
609 | |||
610 | /* copy command_descriptor_block into WD chip | ||
611 | * (take advantage of auto-incrementing) | ||
612 | */ | ||
613 | |||
614 | write_wd33c93_cdb(regs, cmd->cmd_len, cmd->cmnd); | ||
615 | |||
616 | /* The wd33c93 only knows about Group 0, 1, and 5 commands when | ||
617 | * it's doing a 'select-and-transfer'. To be safe, we write the | ||
618 | * size of the CDB into the OWN_ID register for every case. This | ||
619 | * way there won't be problems with vendor-unique, audio, etc. | ||
620 | */ | ||
621 | |||
622 | write_wd33c93(regs, WD_OWN_ID, cmd->cmd_len); | ||
623 | |||
624 | /* When doing a non-disconnect command with DMA, we can save | ||
625 | * ourselves a DATA phase interrupt later by setting everything | ||
626 | * up ahead of time. | ||
627 | */ | ||
628 | |||
629 | if ((cmd->SCp.phase == 0) && (hostdata->no_dma == 0)) { | ||
630 | if (hostdata->dma_setup(cmd, | ||
631 | (cmd->sc_data_direction == DMA_TO_DEVICE) ? | ||
632 | DATA_OUT_DIR : DATA_IN_DIR)) | ||
633 | write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ | ||
634 | else { | ||
635 | write_wd33c93_count(regs, | ||
636 | cmd->SCp.this_residual); | ||
637 | write_wd33c93(regs, WD_CONTROL, | ||
638 | CTRL_IDI | CTRL_EDI | CTRL_DMA); | ||
639 | hostdata->dma = D_DMA_RUNNING; | ||
640 | } | ||
641 | } else | ||
642 | write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ | ||
643 | |||
644 | hostdata->state = S_RUNNING_LEVEL2; | ||
645 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * Since the SCSI bus can handle only 1 connection at a time, | ||
650 | * we get out of here now. If the selection fails, or when | ||
651 | * the command disconnects, we'll come back to this routine | ||
652 | * to search the input_Q again... | ||
653 | */ | ||
654 | |||
655 | DB(DB_EXECUTE, | ||
656 | printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid)) | ||
657 | } | ||
658 | |||
659 | static void | ||
660 | transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt, | ||
661 | int data_in_dir, struct WD33C93_hostdata *hostdata) | ||
662 | { | ||
663 | uchar asr; | ||
664 | |||
665 | DB(DB_TRANSFER, | ||
666 | printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out")) | ||
667 | |||
668 | write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); | ||
669 | write_wd33c93_count(regs, cnt); | ||
670 | write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO); | ||
671 | if (data_in_dir) { | ||
672 | do { | ||
673 | asr = read_aux_stat(regs); | ||
674 | if (asr & ASR_DBR) | ||
675 | *buf++ = read_wd33c93(regs, WD_DATA); | ||
676 | } while (!(asr & ASR_INT)); | ||
677 | } else { | ||
678 | do { | ||
679 | asr = read_aux_stat(regs); | ||
680 | if (asr & ASR_DBR) | ||
681 | write_wd33c93(regs, WD_DATA, *buf++); | ||
682 | } while (!(asr & ASR_INT)); | ||
683 | } | ||
684 | |||
685 | /* Note: we are returning with the interrupt UN-cleared. | ||
686 | * Since (presumably) an entire I/O operation has | ||
687 | * completed, the bus phase is probably different, and | ||
688 | * the interrupt routine will discover this when it | ||
689 | * responds to the uncleared int. | ||
690 | */ | ||
691 | |||
692 | } | ||
693 | |||
694 | static void | ||
695 | transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, | ||
696 | int data_in_dir) | ||
697 | { | ||
698 | struct WD33C93_hostdata *hostdata; | ||
699 | unsigned long length; | ||
700 | |||
701 | hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; | ||
702 | |||
703 | /* Normally, you'd expect 'this_residual' to be non-zero here. | ||
704 | * In a series of scatter-gather transfers, however, this | ||
705 | * routine will usually be called with 'this_residual' equal | ||
706 | * to 0 and 'buffers_residual' non-zero. This means that a | ||
707 | * previous transfer completed, clearing 'this_residual', and | ||
708 | * now we need to setup the next scatter-gather buffer as the | ||
709 | * source or destination for THIS transfer. | ||
710 | */ | ||
711 | if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { | ||
712 | ++cmd->SCp.buffer; | ||
713 | --cmd->SCp.buffers_residual; | ||
714 | cmd->SCp.this_residual = cmd->SCp.buffer->length; | ||
715 | cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + | ||
716 | cmd->SCp.buffer->offset; | ||
717 | } | ||
718 | |||
719 | write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, | ||
720 | hostdata->sync_xfer[cmd->device->id]); | ||
721 | |||
722 | /* 'hostdata->no_dma' is TRUE if we don't even want to try DMA. | ||
723 | * Update 'this_residual' and 'ptr' after 'transfer_pio()' returns. | ||
724 | */ | ||
725 | |||
726 | if (hostdata->no_dma || hostdata->dma_setup(cmd, data_in_dir)) { | ||
727 | #ifdef PROC_STATISTICS | ||
728 | hostdata->pio_cnt++; | ||
729 | #endif | ||
730 | transfer_pio(regs, (uchar *) cmd->SCp.ptr, | ||
731 | cmd->SCp.this_residual, data_in_dir, hostdata); | ||
732 | length = cmd->SCp.this_residual; | ||
733 | cmd->SCp.this_residual = read_wd33c93_count(regs); | ||
734 | cmd->SCp.ptr += (length - cmd->SCp.this_residual); | ||
735 | } | ||
736 | |||
737 | /* We are able to do DMA (in fact, the Amiga hardware is | ||
738 | * already going!), so start up the wd33c93 in DMA mode. | ||
739 | * We set 'hostdata->dma' = D_DMA_RUNNING so that when the | ||
740 | * transfer completes and causes an interrupt, we're | ||
741 | * reminded to tell the Amiga to shut down its end. We'll | ||
742 | * postpone the updating of 'this_residual' and 'ptr' | ||
743 | * until then. | ||
744 | */ | ||
745 | |||
746 | else { | ||
747 | #ifdef PROC_STATISTICS | ||
748 | hostdata->dma_cnt++; | ||
749 | #endif | ||
750 | write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); | ||
751 | write_wd33c93_count(regs, cmd->SCp.this_residual); | ||
752 | |||
753 | if ((hostdata->level2 >= L2_DATA) || | ||
754 | (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { | ||
755 | write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); | ||
756 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
757 | hostdata->state = S_RUNNING_LEVEL2; | ||
758 | } else | ||
759 | write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO); | ||
760 | |||
761 | hostdata->dma = D_DMA_RUNNING; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | void | ||
766 | wd33c93_intr(struct Scsi_Host *instance) | ||
767 | { | ||
768 | struct WD33C93_hostdata *hostdata = | ||
769 | (struct WD33C93_hostdata *) instance->hostdata; | ||
770 | const wd33c93_regs regs = hostdata->regs; | ||
771 | struct scsi_cmnd *patch, *cmd; | ||
772 | uchar asr, sr, phs, id, lun, *ucp, msg; | ||
773 | unsigned long length, flags; | ||
774 | |||
775 | asr = read_aux_stat(regs); | ||
776 | if (!(asr & ASR_INT) || (asr & ASR_BSY)) | ||
777 | return; | ||
778 | |||
779 | spin_lock_irqsave(&hostdata->lock, flags); | ||
780 | |||
781 | #ifdef PROC_STATISTICS | ||
782 | hostdata->int_cnt++; | ||
783 | #endif | ||
784 | |||
785 | cmd = (struct scsi_cmnd *) hostdata->connected; /* assume we're connected */ | ||
786 | sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear the interrupt */ | ||
787 | phs = read_wd33c93(regs, WD_COMMAND_PHASE); | ||
788 | |||
789 | DB(DB_INTR, printk("{%02x:%02x-", asr, sr)) | ||
790 | |||
791 | /* After starting a DMA transfer, the next interrupt | ||
792 | * is guaranteed to be in response to completion of | ||
793 | * the transfer. Since the Amiga DMA hardware runs in | ||
794 | * in an open-ended fashion, it needs to be told when | ||
795 | * to stop; do that here if D_DMA_RUNNING is true. | ||
796 | * Also, we have to update 'this_residual' and 'ptr' | ||
797 | * based on the contents of the TRANSFER_COUNT register, | ||
798 | * in case the device decided to do an intermediate | ||
799 | * disconnect (a device may do this if it has to do a | ||
800 | * seek, or just to be nice and let other devices have | ||
801 | * some bus time during long transfers). After doing | ||
802 | * whatever is needed, we go on and service the WD3393 | ||
803 | * interrupt normally. | ||
804 | */ | ||
805 | if (hostdata->dma == D_DMA_RUNNING) { | ||
806 | DB(DB_TRANSFER, | ||
807 | printk("[%p/%d:", cmd->SCp.ptr, cmd->SCp.this_residual)) | ||
808 | hostdata->dma_stop(cmd->device->host, cmd, 1); | ||
809 | hostdata->dma = D_DMA_OFF; | ||
810 | length = cmd->SCp.this_residual; | ||
811 | cmd->SCp.this_residual = read_wd33c93_count(regs); | ||
812 | cmd->SCp.ptr += (length - cmd->SCp.this_residual); | ||
813 | DB(DB_TRANSFER, | ||
814 | printk("%p/%d]", cmd->SCp.ptr, cmd->SCp.this_residual)) | ||
815 | } | ||
816 | |||
817 | /* Respond to the specific WD3393 interrupt - there are quite a few! */ | ||
818 | switch (sr) { | ||
819 | case CSR_TIMEOUT: | ||
820 | DB(DB_INTR, printk("TIMEOUT")) | ||
821 | |||
822 | if (hostdata->state == S_RUNNING_LEVEL2) | ||
823 | hostdata->connected = NULL; | ||
824 | else { | ||
825 | cmd = (struct scsi_cmnd *) hostdata->selecting; /* get a valid cmd */ | ||
826 | hostdata->selecting = NULL; | ||
827 | } | ||
828 | |||
829 | cmd->result = DID_NO_CONNECT << 16; | ||
830 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
831 | hostdata->state = S_UNCONNECTED; | ||
832 | cmd->scsi_done(cmd); | ||
833 | |||
834 | /* From esp.c: | ||
835 | * There is a window of time within the scsi_done() path | ||
836 | * of execution where interrupts are turned back on full | ||
837 | * blast and left that way. During that time we could | ||
838 | * reconnect to a disconnected command, then we'd bomb | ||
839 | * out below. We could also end up executing two commands | ||
840 | * at _once_. ...just so you know why the restore_flags() | ||
841 | * is here... | ||
842 | */ | ||
843 | |||
844 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
845 | |||
846 | /* We are not connected to a target - check to see if there | ||
847 | * are commands waiting to be executed. | ||
848 | */ | ||
849 | |||
850 | wd33c93_execute(instance); | ||
851 | break; | ||
852 | |||
853 | /* Note: this interrupt should not occur in a LEVEL2 command */ | ||
854 | |||
855 | case CSR_SELECT: | ||
856 | DB(DB_INTR, printk("SELECT")) | ||
857 | hostdata->connected = cmd = | ||
858 | (struct scsi_cmnd *) hostdata->selecting; | ||
859 | hostdata->selecting = NULL; | ||
860 | |||
861 | /* construct an IDENTIFY message with correct disconnect bit */ | ||
862 | |||
863 | hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun); | ||
864 | if (cmd->SCp.phase) | ||
865 | hostdata->outgoing_msg[0] |= 0x40; | ||
866 | |||
867 | if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) { | ||
868 | #ifdef SYNC_DEBUG | ||
869 | printk(" sending SDTR "); | ||
870 | #endif | ||
871 | |||
872 | hostdata->sync_stat[cmd->device->id] = SS_WAITING; | ||
873 | |||
874 | /* Tack on a 2nd message to ask about synchronous transfers. If we've | ||
875 | * been asked to do only asynchronous transfers on this device, we | ||
876 | * request a fifo depth of 0, which is equivalent to async - should | ||
877 | * solve the problems some people have had with GVP's Guru ROM. | ||
878 | */ | ||
879 | |||
880 | hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; | ||
881 | hostdata->outgoing_msg[2] = 3; | ||
882 | hostdata->outgoing_msg[3] = EXTENDED_SDTR; | ||
883 | if (hostdata->no_sync & (1 << cmd->device->id)) { | ||
884 | hostdata->outgoing_msg[4] = | ||
885 | hostdata->default_sx_per / 4; | ||
886 | hostdata->outgoing_msg[5] = 0; | ||
887 | } else { | ||
888 | hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4; | ||
889 | hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; | ||
890 | } | ||
891 | hostdata->outgoing_len = 6; | ||
892 | } else | ||
893 | hostdata->outgoing_len = 1; | ||
894 | |||
895 | hostdata->state = S_CONNECTED; | ||
896 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
897 | break; | ||
898 | |||
899 | case CSR_XFER_DONE | PHS_DATA_IN: | ||
900 | case CSR_UNEXP | PHS_DATA_IN: | ||
901 | case CSR_SRV_REQ | PHS_DATA_IN: | ||
902 | DB(DB_INTR, | ||
903 | printk("IN-%d.%d", cmd->SCp.this_residual, | ||
904 | cmd->SCp.buffers_residual)) | ||
905 | transfer_bytes(regs, cmd, DATA_IN_DIR); | ||
906 | if (hostdata->state != S_RUNNING_LEVEL2) | ||
907 | hostdata->state = S_CONNECTED; | ||
908 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
909 | break; | ||
910 | |||
911 | case CSR_XFER_DONE | PHS_DATA_OUT: | ||
912 | case CSR_UNEXP | PHS_DATA_OUT: | ||
913 | case CSR_SRV_REQ | PHS_DATA_OUT: | ||
914 | DB(DB_INTR, | ||
915 | printk("OUT-%d.%d", cmd->SCp.this_residual, | ||
916 | cmd->SCp.buffers_residual)) | ||
917 | transfer_bytes(regs, cmd, DATA_OUT_DIR); | ||
918 | if (hostdata->state != S_RUNNING_LEVEL2) | ||
919 | hostdata->state = S_CONNECTED; | ||
920 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
921 | break; | ||
922 | |||
923 | /* Note: this interrupt should not occur in a LEVEL2 command */ | ||
924 | |||
925 | case CSR_XFER_DONE | PHS_COMMAND: | ||
926 | case CSR_UNEXP | PHS_COMMAND: | ||
927 | case CSR_SRV_REQ | PHS_COMMAND: | ||
928 | DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid)) | ||
929 | transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, | ||
930 | hostdata); | ||
931 | hostdata->state = S_CONNECTED; | ||
932 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
933 | break; | ||
934 | |||
935 | case CSR_XFER_DONE | PHS_STATUS: | ||
936 | case CSR_UNEXP | PHS_STATUS: | ||
937 | case CSR_SRV_REQ | PHS_STATUS: | ||
938 | DB(DB_INTR, printk("STATUS=")) | ||
939 | cmd->SCp.Status = read_1_byte(regs); | ||
940 | DB(DB_INTR, printk("%02x", cmd->SCp.Status)) | ||
941 | if (hostdata->level2 >= L2_BASIC) { | ||
942 | sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */ | ||
943 | hostdata->state = S_RUNNING_LEVEL2; | ||
944 | write_wd33c93(regs, WD_COMMAND_PHASE, 0x50); | ||
945 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
946 | } else { | ||
947 | hostdata->state = S_CONNECTED; | ||
948 | } | ||
949 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
950 | break; | ||
951 | |||
952 | case CSR_XFER_DONE | PHS_MESS_IN: | ||
953 | case CSR_UNEXP | PHS_MESS_IN: | ||
954 | case CSR_SRV_REQ | PHS_MESS_IN: | ||
955 | DB(DB_INTR, printk("MSG_IN=")) | ||
956 | |||
957 | msg = read_1_byte(regs); | ||
958 | sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */ | ||
959 | |||
960 | hostdata->incoming_msg[hostdata->incoming_ptr] = msg; | ||
961 | if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) | ||
962 | msg = EXTENDED_MESSAGE; | ||
963 | else | ||
964 | hostdata->incoming_ptr = 0; | ||
965 | |||
966 | cmd->SCp.Message = msg; | ||
967 | switch (msg) { | ||
968 | |||
969 | case COMMAND_COMPLETE: | ||
970 | DB(DB_INTR, printk("CCMP-%ld", cmd->pid)) | ||
971 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
972 | hostdata->state = S_PRE_CMP_DISC; | ||
973 | break; | ||
974 | |||
975 | case SAVE_POINTERS: | ||
976 | DB(DB_INTR, printk("SDP")) | ||
977 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
978 | hostdata->state = S_CONNECTED; | ||
979 | break; | ||
980 | |||
981 | case RESTORE_POINTERS: | ||
982 | DB(DB_INTR, printk("RDP")) | ||
983 | if (hostdata->level2 >= L2_BASIC) { | ||
984 | write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); | ||
985 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
986 | hostdata->state = S_RUNNING_LEVEL2; | ||
987 | } else { | ||
988 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
989 | hostdata->state = S_CONNECTED; | ||
990 | } | ||
991 | break; | ||
992 | |||
993 | case DISCONNECT: | ||
994 | DB(DB_INTR, printk("DIS")) | ||
995 | cmd->device->disconnect = 1; | ||
996 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
997 | hostdata->state = S_PRE_TMP_DISC; | ||
998 | break; | ||
999 | |||
1000 | case MESSAGE_REJECT: | ||
1001 | DB(DB_INTR, printk("REJ")) | ||
1002 | #ifdef SYNC_DEBUG | ||
1003 | printk("-REJ-"); | ||
1004 | #endif | ||
1005 | if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) | ||
1006 | hostdata->sync_stat[cmd->device->id] = SS_SET; | ||
1007 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
1008 | hostdata->state = S_CONNECTED; | ||
1009 | break; | ||
1010 | |||
1011 | case EXTENDED_MESSAGE: | ||
1012 | DB(DB_INTR, printk("EXT")) | ||
1013 | |||
1014 | ucp = hostdata->incoming_msg; | ||
1015 | |||
1016 | #ifdef SYNC_DEBUG | ||
1017 | printk("%02x", ucp[hostdata->incoming_ptr]); | ||
1018 | #endif | ||
1019 | /* Is this the last byte of the extended message? */ | ||
1020 | |||
1021 | if ((hostdata->incoming_ptr >= 2) && | ||
1022 | (hostdata->incoming_ptr == (ucp[1] + 1))) { | ||
1023 | |||
1024 | switch (ucp[2]) { /* what's the EXTENDED code? */ | ||
1025 | case EXTENDED_SDTR: | ||
1026 | id = calc_sync_xfer(ucp[3], ucp[4]); | ||
1027 | if (hostdata->sync_stat[cmd->device->id] != | ||
1028 | SS_WAITING) { | ||
1029 | |||
1030 | /* A device has sent an unsolicited SDTR message; rather than go | ||
1031 | * through the effort of decoding it and then figuring out what | ||
1032 | * our reply should be, we're just gonna say that we have a | ||
1033 | * synchronous fifo depth of 0. This will result in asynchronous | ||
1034 | * transfers - not ideal but so much easier. | ||
1035 | * Actually, this is OK because it assures us that if we don't | ||
1036 | * specifically ask for sync transfers, we won't do any. | ||
1037 | */ | ||
1038 | |||
1039 | write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ | ||
1040 | hostdata->outgoing_msg[0] = | ||
1041 | EXTENDED_MESSAGE; | ||
1042 | hostdata->outgoing_msg[1] = 3; | ||
1043 | hostdata->outgoing_msg[2] = | ||
1044 | EXTENDED_SDTR; | ||
1045 | hostdata->outgoing_msg[3] = | ||
1046 | hostdata->default_sx_per / | ||
1047 | 4; | ||
1048 | hostdata->outgoing_msg[4] = 0; | ||
1049 | hostdata->outgoing_len = 5; | ||
1050 | hostdata->sync_xfer[cmd->device->id] = | ||
1051 | calc_sync_xfer(hostdata-> | ||
1052 | default_sx_per | ||
1053 | / 4, 0); | ||
1054 | } else { | ||
1055 | hostdata->sync_xfer[cmd->device->id] = id; | ||
1056 | } | ||
1057 | #ifdef SYNC_DEBUG | ||
1058 | printk("sync_xfer=%02x", | ||
1059 | hostdata->sync_xfer[cmd->device->id]); | ||
1060 | #endif | ||
1061 | hostdata->sync_stat[cmd->device->id] = | ||
1062 | SS_SET; | ||
1063 | write_wd33c93_cmd(regs, | ||
1064 | WD_CMD_NEGATE_ACK); | ||
1065 | hostdata->state = S_CONNECTED; | ||
1066 | break; | ||
1067 | case EXTENDED_WDTR: | ||
1068 | write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ | ||
1069 | printk("sending WDTR "); | ||
1070 | hostdata->outgoing_msg[0] = | ||
1071 | EXTENDED_MESSAGE; | ||
1072 | hostdata->outgoing_msg[1] = 2; | ||
1073 | hostdata->outgoing_msg[2] = | ||
1074 | EXTENDED_WDTR; | ||
1075 | hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ | ||
1076 | hostdata->outgoing_len = 4; | ||
1077 | write_wd33c93_cmd(regs, | ||
1078 | WD_CMD_NEGATE_ACK); | ||
1079 | hostdata->state = S_CONNECTED; | ||
1080 | break; | ||
1081 | default: | ||
1082 | write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ | ||
1083 | printk | ||
1084 | ("Rejecting Unknown Extended Message(%02x). ", | ||
1085 | ucp[2]); | ||
1086 | hostdata->outgoing_msg[0] = | ||
1087 | MESSAGE_REJECT; | ||
1088 | hostdata->outgoing_len = 1; | ||
1089 | write_wd33c93_cmd(regs, | ||
1090 | WD_CMD_NEGATE_ACK); | ||
1091 | hostdata->state = S_CONNECTED; | ||
1092 | break; | ||
1093 | } | ||
1094 | hostdata->incoming_ptr = 0; | ||
1095 | } | ||
1096 | |||
1097 | /* We need to read more MESS_IN bytes for the extended message */ | ||
1098 | |||
1099 | else { | ||
1100 | hostdata->incoming_ptr++; | ||
1101 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
1102 | hostdata->state = S_CONNECTED; | ||
1103 | } | ||
1104 | break; | ||
1105 | |||
1106 | default: | ||
1107 | printk("Rejecting Unknown Message(%02x) ", msg); | ||
1108 | write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ | ||
1109 | hostdata->outgoing_msg[0] = MESSAGE_REJECT; | ||
1110 | hostdata->outgoing_len = 1; | ||
1111 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
1112 | hostdata->state = S_CONNECTED; | ||
1113 | } | ||
1114 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1115 | break; | ||
1116 | |||
1117 | /* Note: this interrupt will occur only after a LEVEL2 command */ | ||
1118 | |||
1119 | case CSR_SEL_XFER_DONE: | ||
1120 | |||
1121 | /* Make sure that reselection is enabled at this point - it may | ||
1122 | * have been turned off for the command that just completed. | ||
1123 | */ | ||
1124 | |||
1125 | write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); | ||
1126 | if (phs == 0x60) { | ||
1127 | DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid)) | ||
1128 | cmd->SCp.Message = COMMAND_COMPLETE; | ||
1129 | lun = read_wd33c93(regs, WD_TARGET_LUN); | ||
1130 | DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) | ||
1131 | hostdata->connected = NULL; | ||
1132 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
1133 | hostdata->state = S_UNCONNECTED; | ||
1134 | if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) | ||
1135 | cmd->SCp.Status = lun; | ||
1136 | if (cmd->cmnd[0] == REQUEST_SENSE | ||
1137 | && cmd->SCp.Status != GOOD) | ||
1138 | cmd->result = | ||
1139 | (cmd-> | ||
1140 | result & 0x00ffff) | (DID_ERROR << 16); | ||
1141 | else | ||
1142 | cmd->result = | ||
1143 | cmd->SCp.Status | (cmd->SCp.Message << 8); | ||
1144 | cmd->scsi_done(cmd); | ||
1145 | |||
1146 | /* We are no longer connected to a target - check to see if | ||
1147 | * there are commands waiting to be executed. | ||
1148 | */ | ||
1149 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1150 | wd33c93_execute(instance); | ||
1151 | } else { | ||
1152 | printk | ||
1153 | ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", | ||
1154 | asr, sr, phs, cmd->pid); | ||
1155 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1156 | } | ||
1157 | break; | ||
1158 | |||
1159 | /* Note: this interrupt will occur only after a LEVEL2 command */ | ||
1160 | |||
1161 | case CSR_SDP: | ||
1162 | DB(DB_INTR, printk("SDP")) | ||
1163 | hostdata->state = S_RUNNING_LEVEL2; | ||
1164 | write_wd33c93(regs, WD_COMMAND_PHASE, 0x41); | ||
1165 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
1166 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1167 | break; | ||
1168 | |||
1169 | case CSR_XFER_DONE | PHS_MESS_OUT: | ||
1170 | case CSR_UNEXP | PHS_MESS_OUT: | ||
1171 | case CSR_SRV_REQ | PHS_MESS_OUT: | ||
1172 | DB(DB_INTR, printk("MSG_OUT=")) | ||
1173 | |||
1174 | /* To get here, we've probably requested MESSAGE_OUT and have | ||
1175 | * already put the correct bytes in outgoing_msg[] and filled | ||
1176 | * in outgoing_len. We simply send them out to the SCSI bus. | ||
1177 | * Sometimes we get MESSAGE_OUT phase when we're not expecting | ||
1178 | * it - like when our SDTR message is rejected by a target. Some | ||
1179 | * targets send the REJECT before receiving all of the extended | ||
1180 | * message, and then seem to go back to MESSAGE_OUT for a byte | ||
1181 | * or two. Not sure why, or if I'm doing something wrong to | ||
1182 | * cause this to happen. Regardless, it seems that sending | ||
1183 | * NOP messages in these situations results in no harm and | ||
1184 | * makes everyone happy. | ||
1185 | */ | ||
1186 | if (hostdata->outgoing_len == 0) { | ||
1187 | hostdata->outgoing_len = 1; | ||
1188 | hostdata->outgoing_msg[0] = NOP; | ||
1189 | } | ||
1190 | transfer_pio(regs, hostdata->outgoing_msg, | ||
1191 | hostdata->outgoing_len, DATA_OUT_DIR, hostdata); | ||
1192 | DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0])) | ||
1193 | hostdata->outgoing_len = 0; | ||
1194 | hostdata->state = S_CONNECTED; | ||
1195 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1196 | break; | ||
1197 | |||
1198 | case CSR_UNEXP_DISC: | ||
1199 | |||
1200 | /* I think I've seen this after a request-sense that was in response | ||
1201 | * to an error condition, but not sure. We certainly need to do | ||
1202 | * something when we get this interrupt - the question is 'what?'. | ||
1203 | * Let's think positively, and assume some command has finished | ||
1204 | * in a legal manner (like a command that provokes a request-sense), | ||
1205 | * so we treat it as a normal command-complete-disconnect. | ||
1206 | */ | ||
1207 | |||
1208 | /* Make sure that reselection is enabled at this point - it may | ||
1209 | * have been turned off for the command that just completed. | ||
1210 | */ | ||
1211 | |||
1212 | write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); | ||
1213 | if (cmd == NULL) { | ||
1214 | printk(" - Already disconnected! "); | ||
1215 | hostdata->state = S_UNCONNECTED; | ||
1216 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1217 | return; | ||
1218 | } | ||
1219 | DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid)) | ||
1220 | hostdata->connected = NULL; | ||
1221 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
1222 | hostdata->state = S_UNCONNECTED; | ||
1223 | if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) | ||
1224 | cmd->result = | ||
1225 | (cmd->result & 0x00ffff) | (DID_ERROR << 16); | ||
1226 | else | ||
1227 | cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); | ||
1228 | cmd->scsi_done(cmd); | ||
1229 | |||
1230 | /* We are no longer connected to a target - check to see if | ||
1231 | * there are commands waiting to be executed. | ||
1232 | */ | ||
1233 | /* look above for comments on scsi_done() */ | ||
1234 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1235 | wd33c93_execute(instance); | ||
1236 | break; | ||
1237 | |||
1238 | case CSR_DISC: | ||
1239 | |||
1240 | /* Make sure that reselection is enabled at this point - it may | ||
1241 | * have been turned off for the command that just completed. | ||
1242 | */ | ||
1243 | |||
1244 | write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); | ||
1245 | DB(DB_INTR, printk("DISC-%ld", cmd->pid)) | ||
1246 | if (cmd == NULL) { | ||
1247 | printk(" - Already disconnected! "); | ||
1248 | hostdata->state = S_UNCONNECTED; | ||
1249 | } | ||
1250 | switch (hostdata->state) { | ||
1251 | case S_PRE_CMP_DISC: | ||
1252 | hostdata->connected = NULL; | ||
1253 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
1254 | hostdata->state = S_UNCONNECTED; | ||
1255 | DB(DB_INTR, printk(":%d", cmd->SCp.Status)) | ||
1256 | if (cmd->cmnd[0] == REQUEST_SENSE | ||
1257 | && cmd->SCp.Status != GOOD) | ||
1258 | cmd->result = | ||
1259 | (cmd-> | ||
1260 | result & 0x00ffff) | (DID_ERROR << 16); | ||
1261 | else | ||
1262 | cmd->result = | ||
1263 | cmd->SCp.Status | (cmd->SCp.Message << 8); | ||
1264 | cmd->scsi_done(cmd); | ||
1265 | break; | ||
1266 | case S_PRE_TMP_DISC: | ||
1267 | case S_RUNNING_LEVEL2: | ||
1268 | cmd->host_scribble = (uchar *) hostdata->disconnected_Q; | ||
1269 | hostdata->disconnected_Q = cmd; | ||
1270 | hostdata->connected = NULL; | ||
1271 | hostdata->state = S_UNCONNECTED; | ||
1272 | |||
1273 | #ifdef PROC_STATISTICS | ||
1274 | hostdata->disc_done_cnt[cmd->device->id]++; | ||
1275 | #endif | ||
1276 | |||
1277 | break; | ||
1278 | default: | ||
1279 | printk("*** Unexpected DISCONNECT interrupt! ***"); | ||
1280 | hostdata->state = S_UNCONNECTED; | ||
1281 | } | ||
1282 | |||
1283 | /* We are no longer connected to a target - check to see if | ||
1284 | * there are commands waiting to be executed. | ||
1285 | */ | ||
1286 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1287 | wd33c93_execute(instance); | ||
1288 | break; | ||
1289 | |||
1290 | case CSR_RESEL_AM: | ||
1291 | case CSR_RESEL: | ||
1292 | DB(DB_INTR, printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : "")) | ||
1293 | |||
1294 | /* Old chips (pre -A ???) don't have advanced features and will | ||
1295 | * generate CSR_RESEL. In that case we have to extract the LUN the | ||
1296 | * hard way (see below). | ||
1297 | * First we have to make sure this reselection didn't | ||
1298 | * happen during Arbitration/Selection of some other device. | ||
1299 | * If yes, put losing command back on top of input_Q. | ||
1300 | */ | ||
1301 | if (hostdata->level2 <= L2_NONE) { | ||
1302 | |||
1303 | if (hostdata->selecting) { | ||
1304 | cmd = (struct scsi_cmnd *) hostdata->selecting; | ||
1305 | hostdata->selecting = NULL; | ||
1306 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
1307 | cmd->host_scribble = | ||
1308 | (uchar *) hostdata->input_Q; | ||
1309 | hostdata->input_Q = cmd; | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | else { | ||
1314 | |||
1315 | if (cmd) { | ||
1316 | if (phs == 0x00) { | ||
1317 | hostdata->busy[cmd->device->id] &= | ||
1318 | ~(1 << cmd->device->lun); | ||
1319 | cmd->host_scribble = | ||
1320 | (uchar *) hostdata->input_Q; | ||
1321 | hostdata->input_Q = cmd; | ||
1322 | } else { | ||
1323 | printk | ||
1324 | ("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", | ||
1325 | asr, sr, phs); | ||
1326 | while (1) | ||
1327 | printk("\r"); | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | } | ||
1332 | |||
1333 | /* OK - find out which device reselected us. */ | ||
1334 | |||
1335 | id = read_wd33c93(regs, WD_SOURCE_ID); | ||
1336 | id &= SRCID_MASK; | ||
1337 | |||
1338 | /* and extract the lun from the ID message. (Note that we don't | ||
1339 | * bother to check for a valid message here - I guess this is | ||
1340 | * not the right way to go, but...) | ||
1341 | */ | ||
1342 | |||
1343 | if (sr == CSR_RESEL_AM) { | ||
1344 | lun = read_wd33c93(regs, WD_DATA); | ||
1345 | if (hostdata->level2 < L2_RESELECT) | ||
1346 | write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); | ||
1347 | lun &= 7; | ||
1348 | } else { | ||
1349 | /* Old chip; wait for msgin phase to pick up the LUN. */ | ||
1350 | for (lun = 255; lun; lun--) { | ||
1351 | if ((asr = read_aux_stat(regs)) & ASR_INT) | ||
1352 | break; | ||
1353 | udelay(10); | ||
1354 | } | ||
1355 | if (!(asr & ASR_INT)) { | ||
1356 | printk | ||
1357 | ("wd33c93: Reselected without IDENTIFY\n"); | ||
1358 | lun = 0; | ||
1359 | } else { | ||
1360 | /* Verify this is a change to MSG_IN and read the message */ | ||
1361 | sr = read_wd33c93(regs, WD_SCSI_STATUS); | ||
1362 | if (sr == (CSR_ABORT | PHS_MESS_IN) || | ||
1363 | sr == (CSR_UNEXP | PHS_MESS_IN) || | ||
1364 | sr == (CSR_SRV_REQ | PHS_MESS_IN)) { | ||
1365 | /* Got MSG_IN, grab target LUN */ | ||
1366 | lun = read_1_byte(regs); | ||
1367 | /* Now we expect a 'paused with ACK asserted' int.. */ | ||
1368 | asr = read_aux_stat(regs); | ||
1369 | if (!(asr & ASR_INT)) { | ||
1370 | udelay(10); | ||
1371 | asr = read_aux_stat(regs); | ||
1372 | if (!(asr & ASR_INT)) | ||
1373 | printk | ||
1374 | ("wd33c93: No int after LUN on RESEL (%02x)\n", | ||
1375 | asr); | ||
1376 | } | ||
1377 | sr = read_wd33c93(regs, WD_SCSI_STATUS); | ||
1378 | if (sr != CSR_MSGIN) | ||
1379 | printk | ||
1380 | ("wd33c93: Not paused with ACK on RESEL (%02x)\n", | ||
1381 | sr); | ||
1382 | lun &= 7; | ||
1383 | write_wd33c93_cmd(regs, | ||
1384 | WD_CMD_NEGATE_ACK); | ||
1385 | } else { | ||
1386 | printk | ||
1387 | ("wd33c93: Not MSG_IN on reselect (%02x)\n", | ||
1388 | sr); | ||
1389 | lun = 0; | ||
1390 | } | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | /* Now we look for the command that's reconnecting. */ | ||
1395 | |||
1396 | cmd = (struct scsi_cmnd *) hostdata->disconnected_Q; | ||
1397 | patch = NULL; | ||
1398 | while (cmd) { | ||
1399 | if (id == cmd->device->id && lun == cmd->device->lun) | ||
1400 | break; | ||
1401 | patch = cmd; | ||
1402 | cmd = (struct scsi_cmnd *) cmd->host_scribble; | ||
1403 | } | ||
1404 | |||
1405 | /* Hmm. Couldn't find a valid command.... What to do? */ | ||
1406 | |||
1407 | if (!cmd) { | ||
1408 | printk | ||
1409 | ("---TROUBLE: target %d.%d not in disconnect queue---", | ||
1410 | id, lun); | ||
1411 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1412 | return; | ||
1413 | } | ||
1414 | |||
1415 | /* Ok, found the command - now start it up again. */ | ||
1416 | |||
1417 | if (patch) | ||
1418 | patch->host_scribble = cmd->host_scribble; | ||
1419 | else | ||
1420 | hostdata->disconnected_Q = | ||
1421 | (struct scsi_cmnd *) cmd->host_scribble; | ||
1422 | hostdata->connected = cmd; | ||
1423 | |||
1424 | /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' | ||
1425 | * because these things are preserved over a disconnect. | ||
1426 | * But we DO need to fix the DPD bit so it's correct for this command. | ||
1427 | */ | ||
1428 | |||
1429 | if (cmd->sc_data_direction == DMA_TO_DEVICE) | ||
1430 | write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id); | ||
1431 | else | ||
1432 | write_wd33c93(regs, WD_DESTINATION_ID, | ||
1433 | cmd->device->id | DSTID_DPD); | ||
1434 | if (hostdata->level2 >= L2_RESELECT) { | ||
1435 | write_wd33c93_count(regs, 0); /* we want a DATA_PHASE interrupt */ | ||
1436 | write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); | ||
1437 | write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); | ||
1438 | hostdata->state = S_RUNNING_LEVEL2; | ||
1439 | } else | ||
1440 | hostdata->state = S_CONNECTED; | ||
1441 | |||
1442 | DB(DB_INTR, printk("-%ld", cmd->pid)) | ||
1443 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1444 | break; | ||
1445 | |||
1446 | default: | ||
1447 | printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs); | ||
1448 | spin_unlock_irqrestore(&hostdata->lock, flags); | ||
1449 | } | ||
1450 | |||
1451 | DB(DB_INTR, printk("} ")) | ||
1452 | |||
1453 | } | ||
1454 | |||
1455 | static void | ||
1456 | reset_wd33c93(struct Scsi_Host *instance) | ||
1457 | { | ||
1458 | struct WD33C93_hostdata *hostdata = | ||
1459 | (struct WD33C93_hostdata *) instance->hostdata; | ||
1460 | const wd33c93_regs regs = hostdata->regs; | ||
1461 | uchar sr; | ||
1462 | |||
1463 | #ifdef CONFIG_SGI_IP22 | ||
1464 | { | ||
1465 | int busycount = 0; | ||
1466 | extern void sgiwd93_reset(unsigned long); | ||
1467 | /* wait 'til the chip gets some time for us */ | ||
1468 | while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100) | ||
1469 | udelay (10); | ||
1470 | /* | ||
1471 | * there are scsi devices out there, which manage to lock up | ||
1472 | * the wd33c93 in a busy condition. In this state it won't | ||
1473 | * accept the reset command. The only way to solve this is to | ||
1474 | * give the chip a hardware reset (if possible). The code below | ||
1475 | * does this for the SGI Indy, where this is possible | ||
1476 | */ | ||
1477 | /* still busy ? */ | ||
1478 | if (read_aux_stat(regs) & ASR_BSY) | ||
1479 | sgiwd93_reset(instance->base); /* yeah, give it the hard one */ | ||
1480 | } | ||
1481 | #endif | ||
1482 | |||
1483 | write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | | ||
1484 | instance->this_id | hostdata->clock_freq); | ||
1485 | write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); | ||
1486 | write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, | ||
1487 | calc_sync_xfer(hostdata->default_sx_per / 4, | ||
1488 | DEFAULT_SX_OFF)); | ||
1489 | write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET); | ||
1490 | |||
1491 | |||
1492 | #ifdef CONFIG_MVME147_SCSI | ||
1493 | udelay(25); /* The old wd33c93 on MVME147 needs this, at least */ | ||
1494 | #endif | ||
1495 | |||
1496 | while (!(read_aux_stat(regs) & ASR_INT)) | ||
1497 | ; | ||
1498 | sr = read_wd33c93(regs, WD_SCSI_STATUS); | ||
1499 | |||
1500 | hostdata->microcode = read_wd33c93(regs, WD_CDB_1); | ||
1501 | if (sr == 0x00) | ||
1502 | hostdata->chip = C_WD33C93; | ||
1503 | else if (sr == 0x01) { | ||
1504 | write_wd33c93(regs, WD_QUEUE_TAG, 0xa5); /* any random number */ | ||
1505 | sr = read_wd33c93(regs, WD_QUEUE_TAG); | ||
1506 | if (sr == 0xa5) { | ||
1507 | hostdata->chip = C_WD33C93B; | ||
1508 | write_wd33c93(regs, WD_QUEUE_TAG, 0); | ||
1509 | } else | ||
1510 | hostdata->chip = C_WD33C93A; | ||
1511 | } else | ||
1512 | hostdata->chip = C_UNKNOWN_CHIP; | ||
1513 | |||
1514 | write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); | ||
1515 | write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); | ||
1516 | } | ||
1517 | |||
1518 | int | ||
1519 | wd33c93_host_reset(struct scsi_cmnd * SCpnt) | ||
1520 | { | ||
1521 | struct Scsi_Host *instance; | ||
1522 | struct WD33C93_hostdata *hostdata; | ||
1523 | int i; | ||
1524 | |||
1525 | instance = SCpnt->device->host; | ||
1526 | hostdata = (struct WD33C93_hostdata *) instance->hostdata; | ||
1527 | |||
1528 | printk("scsi%d: reset. ", instance->host_no); | ||
1529 | disable_irq(instance->irq); | ||
1530 | |||
1531 | hostdata->dma_stop(instance, NULL, 0); | ||
1532 | for (i = 0; i < 8; i++) { | ||
1533 | hostdata->busy[i] = 0; | ||
1534 | hostdata->sync_xfer[i] = | ||
1535 | calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); | ||
1536 | hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ | ||
1537 | } | ||
1538 | hostdata->input_Q = NULL; | ||
1539 | hostdata->selecting = NULL; | ||
1540 | hostdata->connected = NULL; | ||
1541 | hostdata->disconnected_Q = NULL; | ||
1542 | hostdata->state = S_UNCONNECTED; | ||
1543 | hostdata->dma = D_DMA_OFF; | ||
1544 | hostdata->incoming_ptr = 0; | ||
1545 | hostdata->outgoing_len = 0; | ||
1546 | |||
1547 | reset_wd33c93(instance); | ||
1548 | SCpnt->result = DID_RESET << 16; | ||
1549 | enable_irq(instance->irq); | ||
1550 | return SUCCESS; | ||
1551 | } | ||
1552 | |||
1553 | int | ||
1554 | wd33c93_abort(struct scsi_cmnd * cmd) | ||
1555 | { | ||
1556 | struct Scsi_Host *instance; | ||
1557 | struct WD33C93_hostdata *hostdata; | ||
1558 | wd33c93_regs regs; | ||
1559 | struct scsi_cmnd *tmp, *prev; | ||
1560 | |||
1561 | disable_irq(cmd->device->host->irq); | ||
1562 | |||
1563 | instance = cmd->device->host; | ||
1564 | hostdata = (struct WD33C93_hostdata *) instance->hostdata; | ||
1565 | regs = hostdata->regs; | ||
1566 | |||
1567 | /* | ||
1568 | * Case 1 : If the command hasn't been issued yet, we simply remove it | ||
1569 | * from the input_Q. | ||
1570 | */ | ||
1571 | |||
1572 | tmp = (struct scsi_cmnd *) hostdata->input_Q; | ||
1573 | prev = 0; | ||
1574 | while (tmp) { | ||
1575 | if (tmp == cmd) { | ||
1576 | if (prev) | ||
1577 | prev->host_scribble = cmd->host_scribble; | ||
1578 | else | ||
1579 | hostdata->input_Q = | ||
1580 | (struct scsi_cmnd *) cmd->host_scribble; | ||
1581 | cmd->host_scribble = NULL; | ||
1582 | cmd->result = DID_ABORT << 16; | ||
1583 | printk | ||
1584 | ("scsi%d: Abort - removing command %ld from input_Q. ", | ||
1585 | instance->host_no, cmd->pid); | ||
1586 | enable_irq(cmd->device->host->irq); | ||
1587 | cmd->scsi_done(cmd); | ||
1588 | return SUCCESS; | ||
1589 | } | ||
1590 | prev = tmp; | ||
1591 | tmp = (struct scsi_cmnd *) tmp->host_scribble; | ||
1592 | } | ||
1593 | |||
1594 | /* | ||
1595 | * Case 2 : If the command is connected, we're going to fail the abort | ||
1596 | * and let the high level SCSI driver retry at a later time or | ||
1597 | * issue a reset. | ||
1598 | * | ||
1599 | * Timeouts, and therefore aborted commands, will be highly unlikely | ||
1600 | * and handling them cleanly in this situation would make the common | ||
1601 | * case of noresets less efficient, and would pollute our code. So, | ||
1602 | * we fail. | ||
1603 | */ | ||
1604 | |||
1605 | if (hostdata->connected == cmd) { | ||
1606 | uchar sr, asr; | ||
1607 | unsigned long timeout; | ||
1608 | |||
1609 | printk("scsi%d: Aborting connected command %ld - ", | ||
1610 | instance->host_no, cmd->pid); | ||
1611 | |||
1612 | printk("stopping DMA - "); | ||
1613 | if (hostdata->dma == D_DMA_RUNNING) { | ||
1614 | hostdata->dma_stop(instance, cmd, 0); | ||
1615 | hostdata->dma = D_DMA_OFF; | ||
1616 | } | ||
1617 | |||
1618 | printk("sending wd33c93 ABORT command - "); | ||
1619 | write_wd33c93(regs, WD_CONTROL, | ||
1620 | CTRL_IDI | CTRL_EDI | CTRL_POLLED); | ||
1621 | write_wd33c93_cmd(regs, WD_CMD_ABORT); | ||
1622 | |||
1623 | /* Now we have to attempt to flush out the FIFO... */ | ||
1624 | |||
1625 | printk("flushing fifo - "); | ||
1626 | timeout = 1000000; | ||
1627 | do { | ||
1628 | asr = read_aux_stat(regs); | ||
1629 | if (asr & ASR_DBR) | ||
1630 | read_wd33c93(regs, WD_DATA); | ||
1631 | } while (!(asr & ASR_INT) && timeout-- > 0); | ||
1632 | sr = read_wd33c93(regs, WD_SCSI_STATUS); | ||
1633 | printk | ||
1634 | ("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", | ||
1635 | asr, sr, read_wd33c93_count(regs), timeout); | ||
1636 | |||
1637 | /* | ||
1638 | * Abort command processed. | ||
1639 | * Still connected. | ||
1640 | * We must disconnect. | ||
1641 | */ | ||
1642 | |||
1643 | printk("sending wd33c93 DISCONNECT command - "); | ||
1644 | write_wd33c93_cmd(regs, WD_CMD_DISCONNECT); | ||
1645 | |||
1646 | timeout = 1000000; | ||
1647 | asr = read_aux_stat(regs); | ||
1648 | while ((asr & ASR_CIP) && timeout-- > 0) | ||
1649 | asr = read_aux_stat(regs); | ||
1650 | sr = read_wd33c93(regs, WD_SCSI_STATUS); | ||
1651 | printk("asr=%02x, sr=%02x.", asr, sr); | ||
1652 | |||
1653 | hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); | ||
1654 | hostdata->connected = NULL; | ||
1655 | hostdata->state = S_UNCONNECTED; | ||
1656 | cmd->result = DID_ABORT << 16; | ||
1657 | |||
1658 | /* sti();*/ | ||
1659 | wd33c93_execute(instance); | ||
1660 | |||
1661 | enable_irq(cmd->device->host->irq); | ||
1662 | cmd->scsi_done(cmd); | ||
1663 | return SUCCESS; | ||
1664 | } | ||
1665 | |||
1666 | /* | ||
1667 | * Case 3: If the command is currently disconnected from the bus, | ||
1668 | * we're not going to expend much effort here: Let's just return | ||
1669 | * an ABORT_SNOOZE and hope for the best... | ||
1670 | */ | ||
1671 | |||
1672 | tmp = (struct scsi_cmnd *) hostdata->disconnected_Q; | ||
1673 | while (tmp) { | ||
1674 | if (tmp == cmd) { | ||
1675 | printk | ||
1676 | ("scsi%d: Abort - command %ld found on disconnected_Q - ", | ||
1677 | instance->host_no, cmd->pid); | ||
1678 | printk("Abort SNOOZE. "); | ||
1679 | enable_irq(cmd->device->host->irq); | ||
1680 | return FAILED; | ||
1681 | } | ||
1682 | tmp = (struct scsi_cmnd *) tmp->host_scribble; | ||
1683 | } | ||
1684 | |||
1685 | /* | ||
1686 | * Case 4 : If we reached this point, the command was not found in any of | ||
1687 | * the queues. | ||
1688 | * | ||
1689 | * We probably reached this point because of an unlikely race condition | ||
1690 | * between the command completing successfully and the abortion code, | ||
1691 | * so we won't panic, but we will notify the user in case something really | ||
1692 | * broke. | ||
1693 | */ | ||
1694 | |||
1695 | /* sti();*/ | ||
1696 | wd33c93_execute(instance); | ||
1697 | |||
1698 | enable_irq(cmd->device->host->irq); | ||
1699 | printk("scsi%d: warning : SCSI command probably completed successfully" | ||
1700 | " before abortion. ", instance->host_no); | ||
1701 | return FAILED; | ||
1702 | } | ||
1703 | |||
1704 | #define MAX_WD33C93_HOSTS 4 | ||
1705 | #define MAX_SETUP_ARGS ((int)(sizeof(setup_args) / sizeof(char *))) | ||
1706 | #define SETUP_BUFFER_SIZE 200 | ||
1707 | static char setup_buffer[SETUP_BUFFER_SIZE]; | ||
1708 | static char setup_used[MAX_SETUP_ARGS]; | ||
1709 | static int done_setup = 0; | ||
1710 | |||
1711 | int | ||
1712 | wd33c93_setup(char *str) | ||
1713 | { | ||
1714 | int i; | ||
1715 | char *p1, *p2; | ||
1716 | |||
1717 | /* The kernel does some processing of the command-line before calling | ||
1718 | * this function: If it begins with any decimal or hex number arguments, | ||
1719 | * ints[0] = how many numbers found and ints[1] through [n] are the values | ||
1720 | * themselves. str points to where the non-numeric arguments (if any) | ||
1721 | * start: We do our own parsing of those. We construct synthetic 'nosync' | ||
1722 | * keywords out of numeric args (to maintain compatibility with older | ||
1723 | * versions) and then add the rest of the arguments. | ||
1724 | */ | ||
1725 | |||
1726 | p1 = setup_buffer; | ||
1727 | *p1 = '\0'; | ||
1728 | if (str) | ||
1729 | strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer)); | ||
1730 | setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; | ||
1731 | p1 = setup_buffer; | ||
1732 | i = 0; | ||
1733 | while (*p1 && (i < MAX_SETUP_ARGS)) { | ||
1734 | p2 = strchr(p1, ','); | ||
1735 | if (p2) { | ||
1736 | *p2 = '\0'; | ||
1737 | if (p1 != p2) | ||
1738 | setup_args[i] = p1; | ||
1739 | p1 = p2 + 1; | ||
1740 | i++; | ||
1741 | } else { | ||
1742 | setup_args[i] = p1; | ||
1743 | break; | ||
1744 | } | ||
1745 | } | ||
1746 | for (i = 0; i < MAX_SETUP_ARGS; i++) | ||
1747 | setup_used[i] = 0; | ||
1748 | done_setup = 1; | ||
1749 | |||
1750 | return 1; | ||
1751 | } | ||
1752 | __setup("wd33c93=", wd33c93_setup); | ||
1753 | |||
1754 | /* check_setup_args() returns index if key found, 0 if not | ||
1755 | */ | ||
1756 | static int | ||
1757 | check_setup_args(char *key, int *flags, int *val, char *buf) | ||
1758 | { | ||
1759 | int x; | ||
1760 | char *cp; | ||
1761 | |||
1762 | for (x = 0; x < MAX_SETUP_ARGS; x++) { | ||
1763 | if (setup_used[x]) | ||
1764 | continue; | ||
1765 | if (!strncmp(setup_args[x], key, strlen(key))) | ||
1766 | break; | ||
1767 | if (!strncmp(setup_args[x], "next", strlen("next"))) | ||
1768 | return 0; | ||
1769 | } | ||
1770 | if (x == MAX_SETUP_ARGS) | ||
1771 | return 0; | ||
1772 | setup_used[x] = 1; | ||
1773 | cp = setup_args[x] + strlen(key); | ||
1774 | *val = -1; | ||
1775 | if (*cp != ':') | ||
1776 | return ++x; | ||
1777 | cp++; | ||
1778 | if ((*cp >= '0') && (*cp <= '9')) { | ||
1779 | *val = simple_strtoul(cp, NULL, 0); | ||
1780 | } | ||
1781 | return ++x; | ||
1782 | } | ||
1783 | |||
1784 | void | ||
1785 | wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, | ||
1786 | dma_setup_t setup, dma_stop_t stop, int clock_freq) | ||
1787 | { | ||
1788 | struct WD33C93_hostdata *hostdata; | ||
1789 | int i; | ||
1790 | int flags; | ||
1791 | int val; | ||
1792 | char buf[32]; | ||
1793 | |||
1794 | if (!done_setup && setup_strings) | ||
1795 | wd33c93_setup(setup_strings); | ||
1796 | |||
1797 | hostdata = (struct WD33C93_hostdata *) instance->hostdata; | ||
1798 | |||
1799 | hostdata->regs = regs; | ||
1800 | hostdata->clock_freq = clock_freq; | ||
1801 | hostdata->dma_setup = setup; | ||
1802 | hostdata->dma_stop = stop; | ||
1803 | hostdata->dma_bounce_buffer = NULL; | ||
1804 | hostdata->dma_bounce_len = 0; | ||
1805 | for (i = 0; i < 8; i++) { | ||
1806 | hostdata->busy[i] = 0; | ||
1807 | hostdata->sync_xfer[i] = | ||
1808 | calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); | ||
1809 | hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ | ||
1810 | #ifdef PROC_STATISTICS | ||
1811 | hostdata->cmd_cnt[i] = 0; | ||
1812 | hostdata->disc_allowed_cnt[i] = 0; | ||
1813 | hostdata->disc_done_cnt[i] = 0; | ||
1814 | #endif | ||
1815 | } | ||
1816 | hostdata->input_Q = NULL; | ||
1817 | hostdata->selecting = NULL; | ||
1818 | hostdata->connected = NULL; | ||
1819 | hostdata->disconnected_Q = NULL; | ||
1820 | hostdata->state = S_UNCONNECTED; | ||
1821 | hostdata->dma = D_DMA_OFF; | ||
1822 | hostdata->level2 = L2_BASIC; | ||
1823 | hostdata->disconnect = DIS_ADAPTIVE; | ||
1824 | hostdata->args = DEBUG_DEFAULTS; | ||
1825 | hostdata->incoming_ptr = 0; | ||
1826 | hostdata->outgoing_len = 0; | ||
1827 | hostdata->default_sx_per = DEFAULT_SX_PER; | ||
1828 | hostdata->no_sync = 0xff; /* sync defaults to off */ | ||
1829 | hostdata->no_dma = 0; /* default is DMA enabled */ | ||
1830 | |||
1831 | #ifdef PROC_INTERFACE | ||
1832 | hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | | ||
1833 | PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP; | ||
1834 | #ifdef PROC_STATISTICS | ||
1835 | hostdata->dma_cnt = 0; | ||
1836 | hostdata->pio_cnt = 0; | ||
1837 | hostdata->int_cnt = 0; | ||
1838 | #endif | ||
1839 | #endif | ||
1840 | |||
1841 | if (check_setup_args("nosync", &flags, &val, buf)) | ||
1842 | hostdata->no_sync = val; | ||
1843 | |||
1844 | if (check_setup_args("nodma", &flags, &val, buf)) | ||
1845 | hostdata->no_dma = (val == -1) ? 1 : val; | ||
1846 | |||
1847 | if (check_setup_args("period", &flags, &val, buf)) | ||
1848 | hostdata->default_sx_per = | ||
1849 | sx_table[round_period((unsigned int) val)].period_ns; | ||
1850 | |||
1851 | if (check_setup_args("disconnect", &flags, &val, buf)) { | ||
1852 | if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) | ||
1853 | hostdata->disconnect = val; | ||
1854 | else | ||
1855 | hostdata->disconnect = DIS_ADAPTIVE; | ||
1856 | } | ||
1857 | |||
1858 | if (check_setup_args("level2", &flags, &val, buf)) | ||
1859 | hostdata->level2 = val; | ||
1860 | |||
1861 | if (check_setup_args("debug", &flags, &val, buf)) | ||
1862 | hostdata->args = val & DB_MASK; | ||
1863 | |||
1864 | if (check_setup_args("clock", &flags, &val, buf)) { | ||
1865 | if (val > 7 && val < 11) | ||
1866 | val = WD33C93_FS_8_10; | ||
1867 | else if (val > 11 && val < 16) | ||
1868 | val = WD33C93_FS_12_15; | ||
1869 | else if (val > 15 && val < 21) | ||
1870 | val = WD33C93_FS_16_20; | ||
1871 | else | ||
1872 | val = WD33C93_FS_8_10; | ||
1873 | hostdata->clock_freq = val; | ||
1874 | } | ||
1875 | |||
1876 | if ((i = check_setup_args("next", &flags, &val, buf))) { | ||
1877 | while (i) | ||
1878 | setup_used[--i] = 1; | ||
1879 | } | ||
1880 | #ifdef PROC_INTERFACE | ||
1881 | if (check_setup_args("proc", &flags, &val, buf)) | ||
1882 | hostdata->proc = val; | ||
1883 | #endif | ||
1884 | |||
1885 | spin_lock_irq(&hostdata->lock); | ||
1886 | reset_wd33c93(instance); | ||
1887 | spin_unlock_irq(&hostdata->lock); | ||
1888 | |||
1889 | printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d", | ||
1890 | instance->host_no, | ||
1891 | (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == | ||
1892 | C_WD33C93A) ? | ||
1893 | "WD33c93A" : (hostdata->chip == | ||
1894 | C_WD33C93B) ? "WD33c93B" : "unknown", | ||
1895 | hostdata->microcode, hostdata->no_sync, hostdata->no_dma); | ||
1896 | #ifdef DEBUGGING_ON | ||
1897 | printk(" debug_flags=0x%02x\n", hostdata->args); | ||
1898 | #else | ||
1899 | printk(" debugging=OFF\n"); | ||
1900 | #endif | ||
1901 | printk(" setup_args="); | ||
1902 | for (i = 0; i < MAX_SETUP_ARGS; i++) | ||
1903 | printk("%s,", setup_args[i]); | ||
1904 | printk("\n"); | ||
1905 | printk(" Version %s - %s, Compiled %s at %s\n", | ||
1906 | WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__); | ||
1907 | } | ||
1908 | |||
1909 | int | ||
1910 | wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in) | ||
1911 | { | ||
1912 | |||
1913 | #ifdef PROC_INTERFACE | ||
1914 | |||
1915 | char *bp; | ||
1916 | char tbuf[128]; | ||
1917 | struct WD33C93_hostdata *hd; | ||
1918 | struct scsi_cmnd *cmd; | ||
1919 | int x, i; | ||
1920 | static int stop = 0; | ||
1921 | |||
1922 | hd = (struct WD33C93_hostdata *) instance->hostdata; | ||
1923 | |||
1924 | /* If 'in' is TRUE we need to _read_ the proc file. We accept the following | ||
1925 | * keywords (same format as command-line, but only ONE per read): | ||
1926 | * debug | ||
1927 | * disconnect | ||
1928 | * period | ||
1929 | * resync | ||
1930 | * proc | ||
1931 | * nodma | ||
1932 | */ | ||
1933 | |||
1934 | if (in) { | ||
1935 | buf[len] = '\0'; | ||
1936 | bp = buf; | ||
1937 | if (!strncmp(bp, "debug:", 6)) { | ||
1938 | bp += 6; | ||
1939 | hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK; | ||
1940 | } else if (!strncmp(bp, "disconnect:", 11)) { | ||
1941 | bp += 11; | ||
1942 | x = simple_strtoul(bp, NULL, 0); | ||
1943 | if (x < DIS_NEVER || x > DIS_ALWAYS) | ||
1944 | x = DIS_ADAPTIVE; | ||
1945 | hd->disconnect = x; | ||
1946 | } else if (!strncmp(bp, "period:", 7)) { | ||
1947 | bp += 7; | ||
1948 | x = simple_strtoul(bp, NULL, 0); | ||
1949 | hd->default_sx_per = | ||
1950 | sx_table[round_period((unsigned int) x)].period_ns; | ||
1951 | } else if (!strncmp(bp, "resync:", 7)) { | ||
1952 | bp += 7; | ||
1953 | x = simple_strtoul(bp, NULL, 0); | ||
1954 | for (i = 0; i < 7; i++) | ||
1955 | if (x & (1 << i)) | ||
1956 | hd->sync_stat[i] = SS_UNSET; | ||
1957 | } else if (!strncmp(bp, "proc:", 5)) { | ||
1958 | bp += 5; | ||
1959 | hd->proc = simple_strtoul(bp, NULL, 0); | ||
1960 | } else if (!strncmp(bp, "nodma:", 6)) { | ||
1961 | bp += 6; | ||
1962 | hd->no_dma = simple_strtoul(bp, NULL, 0); | ||
1963 | } else if (!strncmp(bp, "level2:", 7)) { | ||
1964 | bp += 7; | ||
1965 | hd->level2 = simple_strtoul(bp, NULL, 0); | ||
1966 | } | ||
1967 | return len; | ||
1968 | } | ||
1969 | |||
1970 | spin_lock_irq(&hd->lock); | ||
1971 | bp = buf; | ||
1972 | *bp = '\0'; | ||
1973 | if (hd->proc & PR_VERSION) { | ||
1974 | sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s", | ||
1975 | WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__); | ||
1976 | strcat(bp, tbuf); | ||
1977 | } | ||
1978 | if (hd->proc & PR_INFO) { | ||
1979 | sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d", | ||
1980 | hd->clock_freq, hd->no_sync, hd->no_dma); | ||
1981 | strcat(bp, tbuf); | ||
1982 | strcat(bp, "\nsync_xfer[] = "); | ||
1983 | for (x = 0; x < 7; x++) { | ||
1984 | sprintf(tbuf, "\t%02x", hd->sync_xfer[x]); | ||
1985 | strcat(bp, tbuf); | ||
1986 | } | ||
1987 | strcat(bp, "\nsync_stat[] = "); | ||
1988 | for (x = 0; x < 7; x++) { | ||
1989 | sprintf(tbuf, "\t%02x", hd->sync_stat[x]); | ||
1990 | strcat(bp, tbuf); | ||
1991 | } | ||
1992 | } | ||
1993 | #ifdef PROC_STATISTICS | ||
1994 | if (hd->proc & PR_STATISTICS) { | ||
1995 | strcat(bp, "\ncommands issued: "); | ||
1996 | for (x = 0; x < 7; x++) { | ||
1997 | sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]); | ||
1998 | strcat(bp, tbuf); | ||
1999 | } | ||
2000 | strcat(bp, "\ndisconnects allowed:"); | ||
2001 | for (x = 0; x < 7; x++) { | ||
2002 | sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]); | ||
2003 | strcat(bp, tbuf); | ||
2004 | } | ||
2005 | strcat(bp, "\ndisconnects done: "); | ||
2006 | for (x = 0; x < 7; x++) { | ||
2007 | sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]); | ||
2008 | strcat(bp, tbuf); | ||
2009 | } | ||
2010 | sprintf(tbuf, | ||
2011 | "\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO", | ||
2012 | hd->int_cnt, hd->dma_cnt, hd->pio_cnt); | ||
2013 | strcat(bp, tbuf); | ||
2014 | } | ||
2015 | #endif | ||
2016 | if (hd->proc & PR_CONNECTED) { | ||
2017 | strcat(bp, "\nconnected: "); | ||
2018 | if (hd->connected) { | ||
2019 | cmd = (struct scsi_cmnd *) hd->connected; | ||
2020 | sprintf(tbuf, " %ld-%d:%d(%02x)", | ||
2021 | cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); | ||
2022 | strcat(bp, tbuf); | ||
2023 | } | ||
2024 | } | ||
2025 | if (hd->proc & PR_INPUTQ) { | ||
2026 | strcat(bp, "\ninput_Q: "); | ||
2027 | cmd = (struct scsi_cmnd *) hd->input_Q; | ||
2028 | while (cmd) { | ||
2029 | sprintf(tbuf, " %ld-%d:%d(%02x)", | ||
2030 | cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); | ||
2031 | strcat(bp, tbuf); | ||
2032 | cmd = (struct scsi_cmnd *) cmd->host_scribble; | ||
2033 | } | ||
2034 | } | ||
2035 | if (hd->proc & PR_DISCQ) { | ||
2036 | strcat(bp, "\ndisconnected_Q:"); | ||
2037 | cmd = (struct scsi_cmnd *) hd->disconnected_Q; | ||
2038 | while (cmd) { | ||
2039 | sprintf(tbuf, " %ld-%d:%d(%02x)", | ||
2040 | cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); | ||
2041 | strcat(bp, tbuf); | ||
2042 | cmd = (struct scsi_cmnd *) cmd->host_scribble; | ||
2043 | } | ||
2044 | } | ||
2045 | strcat(bp, "\n"); | ||
2046 | spin_unlock_irq(&hd->lock); | ||
2047 | *start = buf; | ||
2048 | if (stop) { | ||
2049 | stop = 0; | ||
2050 | return 0; | ||
2051 | } | ||
2052 | if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ | ||
2053 | stop = 1; | ||
2054 | if (hd->proc & PR_STOP) /* stop every other time */ | ||
2055 | stop = 1; | ||
2056 | return strlen(bp); | ||
2057 | |||
2058 | #else /* PROC_INTERFACE */ | ||
2059 | |||
2060 | return 0; | ||
2061 | |||
2062 | #endif /* PROC_INTERFACE */ | ||
2063 | |||
2064 | } | ||
2065 | |||
2066 | void | ||
2067 | wd33c93_release(void) | ||
2068 | { | ||
2069 | } | ||
2070 | |||
2071 | EXPORT_SYMBOL(wd33c93_host_reset); | ||
2072 | EXPORT_SYMBOL(wd33c93_init); | ||
2073 | EXPORT_SYMBOL(wd33c93_release); | ||
2074 | EXPORT_SYMBOL(wd33c93_abort); | ||
2075 | EXPORT_SYMBOL(wd33c93_queuecommand); | ||
2076 | EXPORT_SYMBOL(wd33c93_intr); | ||
2077 | EXPORT_SYMBOL(wd33c93_proc_info); | ||