This source file includes following definitions.
- read_wd33c93
- write_wd33c93
- write_wd33c93_cmd
- read_1_byte
- write_wd33c93_count
- read_wd33c93_count
- calc_sync_xfer
- wd33c93_queuecommand
- wd33c93_execute
- transfer_pio
- transfer_bytes
- wd33c93_intr
- reset_wd33c93
- wd33c93_reset
- wd33c93_abort
- wd33c93_setup
- wd33c93_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 #include <asm/system.h>
67 #include <linux/sched.h>
68 #include <linux/string.h>
69 #include <linux/delay.h>
70 #include <linux/blk.h>
71 #include "scsi.h"
72 #include "hosts.h"
73 #include "wd33c93.h"
74
75
76 #define SYNC_DEBUG
77
78 #define DEBUGGING_ON
79
80 #define WD33C93_VERSION "1.17"
81 #define WD33C93_DATE "06/Feb/1996"
82
83 #ifdef DEBUGGING_ON
84 #define DB(f,a) if (hostdata->args & (f)) a;
85 #else
86 #define DB(f,a)
87 #endif
88
89 #define IS_DIR_OUT(cmd) ((cmd)->cmnd[0] == WRITE_6 || \
90 (cmd)->cmnd[0] == WRITE_10 || \
91 (cmd)->cmnd[0] == WRITE_12)
92
93
94
95
96
97
98
99
100
101
102
103 static unsigned int setup_default = 0;
104
105
106 inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
107 {
108 regp->SASR = reg_num;
109 return(regp->SCMD);
110 }
111
112
113 #define READ_AUX_STAT() (regp->SASR)
114
115
116 inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
117 {
118 regp->SASR = reg_num;
119 regp->SCMD = value;
120 }
121
122
123 inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
124 {
125 regp->SASR = WD_COMMAND;
126 regp->SCMD = cmd;
127 }
128
129
130 inline uchar read_1_byte(wd33c93_regs *regp)
131 {
132 uchar asr;
133 uchar x = 0;
134
135 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
136 write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO|0x80);
137 do {
138 asr = READ_AUX_STAT();
139 if (asr & ASR_DBR)
140 x = read_wd33c93(regp, WD_DATA);
141 } while (!(asr & ASR_INT));
142 return x;
143 }
144
145
146 void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
147 {
148 regp->SASR = WD_TRANSFER_COUNT_MSB;
149 regp->SCMD = value >> 16;
150 regp->SCMD = value >> 8;
151 regp->SCMD = value;
152 }
153
154
155 unsigned long read_wd33c93_count(wd33c93_regs *regp)
156 {
157 unsigned long value;
158
159 regp->SASR = WD_TRANSFER_COUNT_MSB;
160 value = regp->SCMD << 16;
161 value |= regp->SCMD << 8;
162 value |= regp->SCMD;
163 return value;
164 }
165
166
167
168 static struct sx_period sx_table[] = {
169 { 1, 0x20},
170 {252, 0x20},
171 {376, 0x30},
172 {500, 0x40},
173 {624, 0x50},
174 {752, 0x60},
175 {876, 0x70},
176 {1000,0x00},
177 {0, 0} };
178
179 uchar calc_sync_xfer(unsigned int period, unsigned int offset)
180 {
181 uchar result;
182 int x;
183
184 period *= 4;
185 result = 0x00;
186 for (x=1; sx_table[x].period_ns; x++) {
187 if ((period <= sx_table[x-0].period_ns) &&
188 (period > sx_table[x-1].period_ns)) {
189 result = sx_table[x].reg_value;
190 break;
191 }
192 }
193 result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
194 return result;
195 }
196
197
198
199 static void wd33c93_execute(struct Scsi_Host *instance);
200
201 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
202 {
203 struct WD33C93_hostdata *hostdata;
204 Scsi_Cmnd *tmp;
205 unsigned long flags;
206
207 hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
208
209 DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
210
211
212
213
214
215
216
217
218
219 cmd->host_scribble = NULL;
220 cmd->scsi_done = done;
221 cmd->result = 0;
222
223
224
225
226
227
228
229
230
231
232
233
234
235 if (cmd->use_sg) {
236 cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
237 cmd->SCp.buffers_residual = cmd->use_sg - 1;
238 cmd->SCp.ptr = (char *)cmd->SCp.buffer->address;
239 cmd->SCp.this_residual = cmd->SCp.buffer->length;
240 }
241 else {
242 cmd->SCp.buffer = NULL;
243 cmd->SCp.buffers_residual = 0;
244 cmd->SCp.ptr = (char *)cmd->request_buffer;
245 cmd->SCp.this_residual = cmd->request_bufflen;
246 }
247
248
249
250 cmd->SCp.Status = GOOD;
251
252
253
254
255
256
257
258 save_flags(flags);
259 cli();
260 if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
261 cmd->host_scribble = (uchar *)hostdata->input_Q;
262 hostdata->input_Q = cmd;
263 }
264 else {
265 for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
266 tmp=(Scsi_Cmnd *)tmp->host_scribble)
267 ;
268 tmp->host_scribble = (uchar *)cmd;
269 }
270 restore_flags(flags);
271
272
273
274
275
276 wd33c93_execute(cmd->host);
277
278 DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid))
279 return 0;
280 }
281
282
283
284
285
286
287
288
289
290 static void wd33c93_execute (struct Scsi_Host *instance)
291 {
292 struct WD33C93_hostdata *hostdata;
293 wd33c93_regs *regp;
294 Scsi_Cmnd *cmd, *prev;
295 unsigned long flags;
296 int i;
297
298
299 save_flags(flags);
300 cli();
301 hostdata = (struct WD33C93_hostdata *)instance->hostdata;
302 regp = hostdata->regp;
303
304 DB(DB_EXECUTE,printk("EX( "))
305
306 if (hostdata->selecting || hostdata->connected) {
307 DB(DB_EXECUTE,printk(")EX-0 "))
308 restore_flags(flags);
309 return;
310 }
311
312
313
314
315
316
317 cmd = (Scsi_Cmnd *)hostdata->input_Q;
318 prev = 0;
319 while (cmd) {
320 if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))
321 break;
322 prev = cmd;
323 cmd = (Scsi_Cmnd *)cmd->host_scribble;
324 }
325
326
327
328 if (!cmd) {
329 DB(DB_EXECUTE,printk(")EX-1 "))
330 restore_flags(flags);
331 return;
332 }
333
334
335
336 if (prev)
337 prev->host_scribble = cmd->host_scribble;
338 else
339 hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
340 hostdata->selecting = cmd;
341
342
343
344
345
346 if (IS_DIR_OUT(cmd))
347 write_wd33c93(regp, WD_DESTINATION_ID, cmd->target);
348 else
349 write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
350
351 write_wd33c93(regp, WD_TARGET_LUN, cmd->lun);
352 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
353 write_wd33c93_count(regp, 0);
354 hostdata->busy[cmd->target] |= (1 << cmd->lun);
355
356 if ((hostdata->level2 == L2_NONE) ||
357 (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
379 if (hostdata->args & (1 << cmd->target))
380 hostdata->sync_stat[cmd->target] = SS_SET;
381 else
382 hostdata->sync_stat[cmd->target] = SS_FIRST;
383 }
384 hostdata->state = S_SELECTING;
385 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN);
386 }
387
388 else {
389
390
391
392
393
394
395
396
397
398 hostdata->connected = cmd;
399 hostdata->selecting = NULL;
400 write_wd33c93(regp, WD_COMMAND_PHASE, 0);
401
402
403
404 for (i=0; i<cmd->cmd_len; i++)
405 write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]);
406
407
408
409
410
411
412
413 write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len);
414
415 hostdata->state = S_RUNNING_LEVEL2;
416 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
417 }
418
419
420
421
422
423
424
425
426 DB(DB_EXECUTE,printk(")EX-2 "))
427 restore_flags(flags);
428 }
429
430
431
432 void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt,
433 int data_in_dir, struct WD33C93_hostdata *hostdata)
434 {
435 uchar *b, asr;
436 int c;
437
438 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
439 b = *buf;
440 c = *cnt;
441 DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c))
442 write_wd33c93_count(regp,c);
443 write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
444 if (data_in_dir) {
445 do {
446 asr = READ_AUX_STAT();
447 if (asr & ASR_DBR)
448 *b++ = read_wd33c93(regp, WD_DATA);
449 } while (!(asr & ASR_INT));
450 }
451 else {
452 do {
453 asr = READ_AUX_STAT();
454 if (asr & ASR_DBR)
455 write_wd33c93(regp, WD_DATA, *b++);
456 } while (!(asr & ASR_INT));
457 }
458
459
460
461 *cnt = read_wd33c93_count(regp);
462 if (data_in_dir)
463 *buf = b;
464 else
465 *buf += (c - *cnt);
466
467
468
469
470
471
472
473
474 }
475
476
477
478 void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
479 {
480 struct WD33C93_hostdata *hostdata;
481
482 hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
483
484
485
486
487
488
489
490
491
492 if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
493 ++cmd->SCp.buffer;
494 --cmd->SCp.buffers_residual;
495 cmd->SCp.this_residual = cmd->SCp.buffer->length;
496 cmd->SCp.ptr = cmd->SCp.buffer->address;
497 }
498
499 write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
500
501
502
503 if (hostdata->dma_setup(cmd, data_in_dir)) {
504 transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual,
505 data_in_dir, hostdata);
506 }
507
508
509
510
511
512
513
514
515
516
517 else {
518 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
519 DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
520 write_wd33c93_count(regp,cmd->SCp.this_residual);
521
522 if (hostdata->level2 >= L2_DATA) {
523 write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
524 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
525 hostdata->state = S_RUNNING_LEVEL2;
526 }
527 else
528 write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
529
530 hostdata->dma = D_DMA_RUNNING;
531 }
532 }
533
534
535
536 void wd33c93_intr (struct Scsi_Host *instance)
537 {
538 struct WD33C93_hostdata *hostdata;
539 Scsi_Cmnd *patch, *cmd;
540 wd33c93_regs *regp;
541 uchar asr, sr, phs, id, lun, *ucp, msg;
542 unsigned long length;
543 int i;
544
545
546 hostdata = (struct WD33C93_hostdata *)instance->hostdata;
547 regp = hostdata->regp;
548
549 asr = READ_AUX_STAT();
550 if (!(asr & ASR_INT) || (asr & ASR_BSY))
551 return;
552
553 cmd = (Scsi_Cmnd *)hostdata->connected;
554 sr = read_wd33c93(regp, WD_SCSI_STATUS);
555 phs = read_wd33c93(regp, WD_COMMAND_PHASE);
556
557 DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574 if (hostdata->dma == D_DMA_RUNNING) {
575 DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
576 hostdata->dma_stop(cmd->host, cmd, 1);
577 hostdata->dma = D_DMA_OFF;
578 length = cmd->SCp.this_residual;
579 cmd->SCp.this_residual = read_wd33c93_count(regp);
580 cmd->SCp.ptr += (length - cmd->SCp.this_residual);
581 DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
582 }
583
584
585
586 switch (sr) {
587
588 case CSR_TIMEOUT:
589 cli();
590 DB(DB_INTR,printk("TIMEOUT"))
591 if (hostdata->state == S_RUNNING_LEVEL2) {
592 hostdata->connected = NULL;
593 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
594 }
595 else {
596 cmd = (Scsi_Cmnd *)hostdata->selecting;
597 hostdata->selecting = NULL;
598 }
599
600 cmd->result = DID_NO_CONNECT << 16;
601 hostdata->selecting = NULL;
602 hostdata->state = S_UNCONNECTED;
603 cmd->scsi_done(cmd);
604
605
606
607
608
609 wd33c93_execute(instance);
610 break;
611
612
613
614
615 case CSR_SELECT:
616 cli();
617 DB(DB_INTR,printk("SELECT"))
618 hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
619 hostdata->selecting = NULL;
620
621
622
623 if (hostdata->args & A_NO_DISCONNECT)
624 hostdata->outgoing_msg[0] = (0x80 | cmd->lun);
625 else
626 hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun);
627
628 if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
629 #ifdef SYNC_DEBUG
630 printk(" sending SDTR ");
631 #endif
632
633 hostdata->sync_stat[cmd->target] = SS_WAITING;
634
635
636
637 hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
638 hostdata->outgoing_msg[2] = 3;
639 hostdata->outgoing_msg[3] = EXTENDED_SDTR;
640 hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
641 hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
642 hostdata->outgoing_len = 6;
643 }
644 else
645 hostdata->outgoing_len = 1;
646
647 hostdata->state = S_CONNECTED;
648 break;
649
650
651 case CSR_XFER_DONE|PHS_DATA_IN:
652 case CSR_UNEXP |PHS_DATA_IN:
653 case CSR_SRV_REQ |PHS_DATA_IN:
654 DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
655 transfer_bytes(regp, cmd, DATA_IN_DIR);
656 if (hostdata->state != S_RUNNING_LEVEL2)
657 hostdata->state = S_CONNECTED;
658 break;
659
660
661 case CSR_XFER_DONE|PHS_DATA_OUT:
662 case CSR_UNEXP |PHS_DATA_OUT:
663 case CSR_SRV_REQ |PHS_DATA_OUT:
664 DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
665 transfer_bytes(regp, cmd, DATA_OUT_DIR);
666 if (hostdata->state != S_RUNNING_LEVEL2)
667 hostdata->state = S_CONNECTED;
668 break;
669
670
671
672
673 case CSR_XFER_DONE|PHS_COMMAND:
674 case CSR_SRV_REQ |PHS_COMMAND:
675 DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
676 ucp = cmd->cmnd;
677 i = cmd->cmd_len;
678 transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
679 hostdata->state = S_CONNECTED;
680 break;
681
682
683 case CSR_XFER_DONE|PHS_STATUS:
684 case CSR_UNEXP |PHS_STATUS:
685 case CSR_SRV_REQ |PHS_STATUS:
686 DB(DB_INTR,printk("STATUS"))
687
688 cmd->SCp.Status = read_1_byte(regp);
689 if (hostdata->level2 >= L2_BASIC) {
690 sr = read_wd33c93(regp, WD_SCSI_STATUS);
691 hostdata->state = S_RUNNING_LEVEL2;
692 write_wd33c93(regp, WD_COMMAND_PHASE, 0x50);
693 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
694 }
695 else {
696 DB(DB_INTR,printk("=%02x",cmd->SCp.Status))
697 hostdata->state = S_CONNECTED;
698 }
699 break;
700
701
702 case CSR_XFER_DONE|PHS_MESS_IN:
703 case CSR_UNEXP |PHS_MESS_IN:
704 case CSR_SRV_REQ |PHS_MESS_IN:
705 DB(DB_INTR,printk("MSG_IN="))
706
707 msg = read_1_byte(regp);
708 sr = read_wd33c93(regp, WD_SCSI_STATUS);
709
710 hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
711 if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
712 msg = EXTENDED_MESSAGE;
713 else
714 hostdata->incoming_ptr = 0;
715
716 cmd->SCp.Message = msg;
717 switch (msg) {
718
719 case COMMAND_COMPLETE:
720 DB(DB_INTR,printk("CCMP-%ld",cmd->pid))
721 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
722 hostdata->state = S_PRE_CMP_DISC;
723 break;
724
725 case SAVE_POINTERS:
726 DB(DB_INTR,printk("SDP"))
727 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
728 hostdata->state = S_CONNECTED;
729 break;
730
731 case RESTORE_POINTERS:
732 DB(DB_INTR,printk("RDP"))
733
734 if (hostdata->level2 >= L2_BASIC) {
735 write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
736 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
737 hostdata->state = S_RUNNING_LEVEL2;
738 }
739 else {
740 write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK);
741 hostdata->state = S_CONNECTED;
742 }
743 break;
744
745 case DISCONNECT:
746 DB(DB_INTR,printk("DIS"))
747 cmd->device->disconnect = 1;
748 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
749 hostdata->state = S_PRE_TMP_DISC;
750 break;
751
752 case MESSAGE_REJECT:
753 DB(DB_INTR,printk("REJ"))
754 #ifdef SYNC_DEBUG
755 printk("-REJ-");
756 #endif
757 if (hostdata->sync_stat[cmd->target] == SS_WAITING)
758 hostdata->sync_stat[cmd->target] = SS_SET;
759 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
760 hostdata->state = S_CONNECTED;
761 break;
762
763 case EXTENDED_MESSAGE:
764 DB(DB_INTR,printk("EXT"))
765
766 ucp = hostdata->incoming_msg;
767
768 #ifdef SYNC_DEBUG
769 printk("%02x",ucp[hostdata->incoming_ptr]);
770 #endif
771
772
773 if ((hostdata->incoming_ptr >= 2) &&
774 (hostdata->incoming_ptr == (ucp[1] + 1))) {
775
776 switch (ucp[2]) {
777 case EXTENDED_SDTR:
778 id = calc_sync_xfer(ucp[3],ucp[4]);
779 if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
780 printk("Rejecting target's SDTR message ");
781 write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN);
782 hostdata->outgoing_msg[0] = MESSAGE_REJECT;
783 hostdata->outgoing_len = 1;
784 }
785 else {
786 hostdata->sync_xfer[cmd->target] = id;
787 hostdata->sync_stat[cmd->target] = SS_SET;
788 }
789 #ifdef SYNC_DEBUG
790 printk("sync_xfer=%02x",id);
791 #endif
792 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
793 hostdata->state = S_CONNECTED;
794 break;
795 default:
796 printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
797 write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN);
798 hostdata->outgoing_msg[0] = MESSAGE_REJECT;
799 hostdata->outgoing_len = 1;
800 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
801 hostdata->state = S_CONNECTED;
802 break;
803 }
804 hostdata->incoming_ptr = 0;
805 }
806
807
808
809 else {
810 hostdata->incoming_ptr++;
811 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
812 hostdata->state = S_CONNECTED;
813 }
814 break;
815
816 default:
817 printk("Rejecting Unknown Message(%02x) ",ucp[0]);
818 write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN);
819 hostdata->outgoing_msg[0] = MESSAGE_REJECT;
820 hostdata->outgoing_len = 1;
821 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
822 hostdata->state = S_CONNECTED;
823 }
824 break;
825
826
827
828
829 case CSR_SEL_XFER_DONE:
830 cli();
831 if (phs == 0x60) {
832 DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
833 cmd->SCp.Message = COMMAND_COMPLETE;
834 lun = read_wd33c93(regp, WD_TARGET_LUN);
835 if (cmd->SCp.Status == GOOD)
836 cmd->SCp.Status = lun;
837 hostdata->connected = NULL;
838 if (cmd->cmnd[0] != REQUEST_SENSE)
839 cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
840 else if (cmd->SCp.Status != GOOD)
841 cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
842 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
843 hostdata->state = S_UNCONNECTED;
844 cmd->scsi_done(cmd);
845
846
847
848
849
850 wd33c93_execute(instance);
851 }
852 else {
853 printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid);
854 }
855 break;
856
857
858
859
860 case CSR_SDP:
861 DB(DB_INTR,printk("SDP"))
862 hostdata->state = S_RUNNING_LEVEL2;
863 write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
864 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
865 break;
866
867
868 case CSR_XFER_DONE|PHS_MESS_OUT:
869 case CSR_UNEXP |PHS_MESS_OUT:
870 case CSR_SRV_REQ |PHS_MESS_OUT:
871 DB(DB_INTR,printk("MSG_OUT="))
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886 if (hostdata->outgoing_len == 0) {
887 hostdata->outgoing_len = 1;
888 hostdata->outgoing_msg[0] = NOP;
889 }
890 ucp = hostdata->outgoing_msg;
891 i = hostdata->outgoing_len;
892 transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
893 DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
894 hostdata->outgoing_len = 0;
895 hostdata->state = S_CONNECTED;
896 break;
897
898
899 case CSR_DISC:
900 DB(DB_INTR,printk("DISC"))
901 if (cmd == NULL) {
902 printk(" - Already disconnected! ");
903 hostdata->state = S_UNCONNECTED;
904 return;
905 }
906 switch (hostdata->state) {
907 case S_PRE_CMP_DISC:
908 hostdata->connected = NULL;
909 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
910 hostdata->state = S_UNCONNECTED;
911 if (cmd->cmnd[0] != REQUEST_SENSE)
912 cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
913 else if (cmd->SCp.Status != GOOD)
914 cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
915 cmd->scsi_done(cmd);
916 break;
917 case S_PRE_TMP_DISC:
918 case S_RUNNING_LEVEL2:
919 cmd->host_scribble = (uchar *)hostdata->disconnected_Q;
920 hostdata->disconnected_Q = cmd;
921 hostdata->connected = NULL;
922 hostdata->state = S_UNCONNECTED;
923 break;
924 default:
925 printk("*** Unexpected DISCONNECT interrupt! ***");
926 hostdata->state = S_UNCONNECTED;
927 }
928
929
930
931
932
933 wd33c93_execute(instance);
934 break;
935
936
937 case CSR_RESEL_AM:
938 DB(DB_INTR,printk("RESEL"))
939
940 cli();
941
942
943
944
945
946 if (hostdata->level2 == L2_NONE) {
947
948 if (hostdata->selecting) {
949 cmd = (Scsi_Cmnd *)hostdata->selecting;
950 hostdata->selecting = NULL;
951 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
952 cmd->host_scribble = (uchar *)hostdata->input_Q;
953 hostdata->input_Q = cmd;
954 }
955 }
956
957 else {
958
959 if (cmd) {
960 if (phs == 0x00) {
961 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
962 cmd->host_scribble = (uchar *)hostdata->input_Q;
963 hostdata->input_Q = cmd;
964 }
965 else {
966 printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs);
967 while (1)
968 printk("\r");
969 }
970 }
971
972 }
973
974
975
976 id = read_wd33c93(regp, WD_SOURCE_ID);
977 id &= SRCID_MASK;
978
979
980
981
982
983
984 lun = read_wd33c93(regp, WD_DATA);
985 if (hostdata->level2 < L2_RESELECT)
986 write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
987 lun &= 7;
988
989
990
991 cmd = (Scsi_Cmnd *)hostdata->disconnected_Q;
992 patch = NULL;
993 while (cmd) {
994 if (id == cmd->target && lun == cmd->lun)
995 break;
996 patch = cmd;
997 cmd = (Scsi_Cmnd *)cmd->host_scribble;
998 }
999
1000
1001
1002 if (!cmd) {
1003 printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun);
1004 return;
1005 }
1006
1007
1008
1009 if (patch)
1010 patch->host_scribble = cmd->host_scribble;
1011 else
1012 hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble;
1013 hostdata->connected = cmd;
1014
1015
1016
1017
1018
1019
1020 if (IS_DIR_OUT(cmd))
1021 write_wd33c93(regp, WD_DESTINATION_ID, cmd->target);
1022 else
1023 write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
1024 if (hostdata->level2 >= L2_RESELECT) {
1025 write_wd33c93_count(regp, 0);
1026 write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
1027 write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
1028 hostdata->state = S_RUNNING_LEVEL2;
1029 }
1030 else
1031 hostdata->state = S_CONNECTED;
1032
1033 DB(DB_INTR,printk("-%ld",cmd->pid))
1034 break;
1035
1036 default:
1037 printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs);
1038 }
1039
1040 DB(DB_INTR,printk("} "))
1041
1042 }
1043
1044
1045
1046 void reset_wd33c93(struct Scsi_Host *instance)
1047 {
1048 struct WD33C93_hostdata *hostdata;
1049 wd33c93_regs *regp;
1050 uchar sr;
1051
1052 hostdata = (struct WD33C93_hostdata *)instance->hostdata;
1053 regp = hostdata->regp;
1054
1055 write_wd33c93(regp, WD_OWN_ID, OWNID_EAF | OWNID_RAF |
1056 instance->this_id | hostdata->clock_freq);
1057 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1058 write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER,
1059 calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF));
1060 write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET);
1061
1062 while (!(READ_AUX_STAT() & ASR_INT))
1063 ;
1064 sr = read_wd33c93(regp, WD_SCSI_STATUS);
1065
1066 hostdata->microcode = read_wd33c93(regp, WD_CDB_1);
1067 if (sr == 0x00)
1068 hostdata->chip = C_WD33C93;
1069 else if (sr == 0x01) {
1070 write_wd33c93(regp, WD_QUEUE_TAG, 0xa5);
1071 sr = read_wd33c93(regp, WD_QUEUE_TAG);
1072 if (sr == 0xa5) {
1073 hostdata->chip = C_WD33C93B;
1074 write_wd33c93(regp, WD_QUEUE_TAG, 0);
1075 }
1076 else
1077 hostdata->chip = C_WD33C93A;
1078 }
1079 else
1080 hostdata->chip = C_UNKNOWN_CHIP;
1081
1082 write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
1083 if (hostdata->args & A_NO_DISCONNECT)
1084 write_wd33c93(regp, WD_SOURCE_ID, 0);
1085 else
1086 write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER);
1087 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1088 }
1089
1090
1091
1092 int wd33c93_reset(Scsi_Cmnd *SCpnt)
1093 {
1094 unsigned long flags;
1095 struct Scsi_Host *instance;
1096
1097 instance = SCpnt->host;
1098
1099 printk("scsi%d: reset. ", instance->host_no);
1100 save_flags(flags);
1101 cli();
1102 ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0);
1103 reset_wd33c93(instance);
1104 SCpnt->result = DID_RESET << 16;
1105 restore_flags(flags);
1106 return 0;
1107 }
1108
1109
1110
1111 int wd33c93_abort (Scsi_Cmnd *cmd)
1112 {
1113 struct Scsi_Host *instance;
1114 struct WD33C93_hostdata *hostdata;
1115 wd33c93_regs *regp;
1116 Scsi_Cmnd *tmp, **prev;
1117 unsigned long flags;
1118
1119 instance = cmd->host;
1120 hostdata = (struct WD33C93_hostdata *)instance->hostdata;
1121 regp = hostdata->regp;
1122
1123 printk ("scsi%d: abort. ", instance->host_no);
1124
1125 save_flags (flags);
1126 cli();
1127
1128
1129
1130
1131
1132 for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q;
1133 tmp;
1134 prev=(Scsi_Cmnd **)&(tmp->host_scribble),tmp=(Scsi_Cmnd *)tmp->host_scribble)
1135 if (cmd == tmp) {
1136 (*prev) = (Scsi_Cmnd *)tmp->host_scribble;
1137 tmp->host_scribble = NULL;
1138 tmp->result = DID_ABORT << 16;
1139 restore_flags(flags);
1140 printk("scsi%d : abort removed command from issue queue. ",
1141 instance->host_no);
1142 tmp->scsi_done(tmp);
1143 return SCSI_ABORT_SUCCESS;
1144 }
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 if (hostdata->connected == cmd) {
1158 uchar sr, asr;
1159 unsigned long timeout;
1160
1161 printk("scsi%d : aborting connected command. ", instance->host_no);
1162
1163 if (hostdata->dma == D_DMA_RUNNING) {
1164 hostdata->dma_stop(instance, cmd, 0);
1165 hostdata->dma = D_DMA_OFF;
1166 }
1167
1168 printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT());
1169
1170 write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1171 write_wd33c93_cmd(regp, WD_CMD_ABORT);
1172
1173
1174
1175 timeout = 1000000;
1176 do {
1177 asr = READ_AUX_STAT();
1178 if (asr & ASR_DBR)
1179 read_wd33c93(regp, WD_DATA);
1180 } while (!(asr & ASR_INT) && timeout-- > 0);
1181 sr = read_wd33c93(regp, WD_SCSI_STATUS);
1182 printk("scsi%d : wd33c93 sr is %x. ", instance->host_no,
1183 read_wd33c93(regp, WD_SCSI_STATUS));
1184
1185 if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) {
1186
1187
1188
1189
1190
1191 printk("scsi%d : count was %ld. ", instance->host_no,
1192 read_wd33c93_count(regp));
1193
1194 timeout = 1000000;
1195 while ((asr & ASR_CIP) && timeout-- > 0)
1196 asr = READ_AUX_STAT();
1197 write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
1198 asr = READ_AUX_STAT();
1199 if (asr & ASR_LCI)
1200 printk ("scsi%d: disconnect command ignored. ",
1201 instance->host_no);
1202 timeout = 1000000;
1203 while ((asr & ASR_CIP) && timeout-- > 0)
1204 asr = READ_AUX_STAT();
1205 }
1206 asr = READ_AUX_STAT();
1207 sr = read_wd33c93(regp, WD_SCSI_STATUS);
1208 printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
1209 write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
1210 timeout = 1000000;
1211 while ((asr & ASR_CIP) && timeout-- > 0)
1212 asr = READ_AUX_STAT();
1213 sr = read_wd33c93(regp, WD_SCSI_STATUS);
1214 printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
1215 reset_wd33c93(instance);
1216 cmd->result = DID_ABORT << 16;
1217 cmd->scsi_done(cmd);
1218 hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
1219 hostdata->connected = NULL;
1220 hostdata->state = S_UNCONNECTED;
1221 wd33c93_execute (instance);
1222 restore_flags(flags);
1223 return SCSI_ABORT_SUCCESS;
1224 }
1225
1226
1227
1228
1229
1230
1231
1232 for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
1233 tmp=(Scsi_Cmnd *)tmp->host_scribble)
1234 if (cmd == tmp) {
1235 restore_flags(flags);
1236 return SCSI_ABORT_SNOOZE;
1237 }
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249 restore_flags(flags);
1250 printk("scsi%d : warning : SCSI command probably completed successfully\n"
1251 " before abortion. ", instance->host_no);
1252 return SCSI_ABORT_NOT_RUNNING;
1253 }
1254
1255
1256
1257 #define MAX_WD33C93_HOSTS 8
1258 static unsigned int setup_args_array[MAX_WD33C93_HOSTS];
1259 static int setup_args_array_x = 0;
1260
1261 void wd33c93_setup (char *str, int *ints)
1262 {
1263 int i;
1264
1265 for (i=0; i<ints[0]; i++) {
1266 setup_args_array[i] = ints[i+1];
1267 }
1268 }
1269
1270
1271
1272 void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
1273 dma_setup_t setup, dma_stop_t stop, int clock_freq)
1274 {
1275 struct WD33C93_hostdata *hostdata;
1276 int i;
1277
1278 hostdata = (struct WD33C93_hostdata *)instance->hostdata;
1279
1280 hostdata->regp = regs;
1281 hostdata->clock_freq = clock_freq;
1282 hostdata->dma_setup = setup;
1283 hostdata->dma_stop = stop;
1284 hostdata->dma_bounce_buffer = NULL;
1285 hostdata->dma_bounce_len = 0;
1286 for (i = 0; i < 8; i++) {
1287 hostdata->busy[i] = 0;
1288 hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
1289 hostdata->sync_stat[i] = SS_UNSET;
1290 }
1291 hostdata->input_Q = NULL;
1292 hostdata->selecting = NULL;
1293 hostdata->connected = NULL;
1294 hostdata->disconnected_Q = NULL;
1295 hostdata->state = S_UNCONNECTED;
1296 hostdata->dma = D_DMA_OFF;
1297 hostdata->incoming_ptr = 0;
1298 hostdata->outgoing_len = 0;
1299
1300 hostdata->args = setup_default;
1301 if ((setup_args_array_x < MAX_WD33C93_HOSTS) &&
1302 (setup_args_array[setup_args_array_x]))
1303 hostdata->args = setup_args_array[setup_args_array_x];
1304 setup_args_array_x++;
1305
1306 i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2);
1307 i >>= 8;
1308 if (i == 0)
1309 i = L2_DEFAULT;
1310 hostdata->level2 = i;
1311
1312 cli();
1313 reset_wd33c93(instance);
1314 sti();
1315
1316 printk("wd33c93-%d: ",instance->host_no);
1317 switch (hostdata->chip) {
1318 case C_WD33C93:
1319 printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n");
1320 break;
1321 case C_WD33C93A:
1322 printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode);
1323 break;
1324 case C_WD33C93B:
1325 printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode);
1326 break;
1327 default:
1328 printk("Unknown 3393 chip!\n");
1329 }
1330 printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no,
1331 (hostdata->level2 == L2_NONE)?"disabled":"enabled",
1332 hostdata->level2);
1333 #ifdef DEBUGGING_ON
1334 printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args);
1335 #endif
1336 printk("wd33c93-%d: driver version %s - %s\n",instance->host_no,
1337 WD33C93_VERSION,WD33C93_DATE);
1338 }
1339