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