This source file includes following definitions.
- wd7000_enable_intr
- wd7000_enable_dma
- delay
- command_out
- alloc_scb
- free_scb
- init_scbs
- mail_out
- make_code
- wd7000_scsi_done
- wd7000_intr_handle
- wd7000_queuecommand
- wd7000_command
- wd7000_init
- wd7000_revision
- wd7000_detect
- wd7000_append_info
- wd7000_info
- wd7000_abort
- wd7000_reset
- wd7000_biosparam
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <stdarg.h>
15 #include <linux/kernel.h>
16 #include <linux/head.h>
17 #include <linux/types.h>
18 #include <linux/string.h>
19 #include <linux/sched.h>
20 #include <asm/system.h>
21 #include <asm/dma.h>
22 #include <asm/io.h>
23 #include <linux/ioport.h>
24
25 #include "../block/blk.h"
26 #include "scsi.h"
27 #include "hosts.h"
28
29
30
31 #include "wd7000.h"
32
33
34 #ifdef DEBUG
35 #define DEB(x) x
36 #else
37 #define DEB(x)
38 #endif
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 static struct {
67 struct wd_mailbox ogmb[OGMB_CNT];
68 struct wd_mailbox icmb[ICMB_CNT];
69 } mb;
70 static int next_ogmb = 0;
71
72 static Scb scbs[MAX_SCBS];
73 static Scb *scbfree = NULL;
74
75 static int wd7000_host = 0;
76 static unchar controlstat = 0;
77
78 static unchar rev_1 = 0, rev_2 = 0;
79
80 #define wd7000_intr_ack() outb(0,INTR_ACK)
81
82 #define WAITnexttimeout 3000000
83
84
85 static inline void wd7000_enable_intr(void)
86 {
87 controlstat |= INT_EN;
88 outb(controlstat,CONTROL);
89 }
90
91
92 static inline void wd7000_enable_dma(void)
93 {
94 controlstat |= DMA_EN;
95 outb(controlstat,CONTROL);
96 set_dma_mode(DMA_CH, DMA_MODE_CASCADE);
97 enable_dma(DMA_CH);
98 }
99
100
101 #define WAIT(port, mask, allof, noneof) \
102 { register WAITbits; \
103 register WAITtimeout = WAITnexttimeout; \
104 while (1) { \
105 WAITbits = inb(port) & (mask); \
106 if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
107 break; \
108 if (--WAITtimeout == 0) goto fail; \
109 } \
110 }
111
112
113 static inline void delay( unsigned how_long )
114 {
115 unsigned long time = jiffies + how_long;
116
117 while (jiffies < time);
118 }
119
120
121 static inline int command_out(unchar *cmdp, int len)
122 {
123 while (len--) {
124 WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
125 outb(*cmdp++, COMMAND);
126 }
127 return 1;
128
129 fail:
130 printk("wd7000_out WAIT failed(%d): ", len+1);
131 return 0;
132 }
133
134 static inline Scb *alloc_scb(void)
135 {
136 Scb *scb;
137 unsigned long flags;
138
139 save_flags(flags);
140 cli();
141
142 if (scbfree == NULL) {
143 panic("wd7000: can't allocate free SCB.\n");
144 restore_flags(flags);
145 return NULL;
146 }
147 scb = scbfree; scbfree = scb->next;
148 memset(scb, 0, sizeof(Scb)); scb->next = NULL;
149
150 restore_flags(flags);
151
152 return scb;
153 }
154
155
156 static inline void free_scb( Scb *scb )
157 {
158 unsigned long flags;
159
160 save_flags(flags);
161 cli();
162
163 memset(scb, 0, sizeof(Scb));
164 scb->next = scbfree; scbfree = scb;
165
166 restore_flags(flags);
167 }
168
169
170 static inline void init_scbs(void)
171 {
172 int i;
173 unsigned long flags;
174
175 save_flags(flags);
176 cli();
177
178 scbfree = &(scbs[0]);
179 for (i = 0; i < MAX_SCBS-1; i++) scbs[i].next = &(scbs[i+1]);
180 scbs[MAX_SCBS-1].next = NULL;
181
182 restore_flags(flags);
183 }
184
185
186 static int mail_out( Scb *scbptr )
187
188
189
190 {
191 int i, ogmb;
192 unsigned long flags;
193
194 DEB(printk("wd7000_scb_out: %06x");)
195
196
197 save_flags(flags);
198 cli();
199 ogmb = next_ogmb;
200 for (i = 0; i < OGMB_CNT; i++) {
201 if (mb.ogmb[ogmb].status == 0) {
202 DEB(printk(" using OGMB %x",ogmb));
203 mb.ogmb[ogmb].status = 1;
204 any2scsi(mb.ogmb[ogmb].scbptr, scbptr);
205
206 next_ogmb = (ogmb+1) % OGMB_CNT;
207 break;
208 } else
209 ogmb = (++ogmb) % OGMB_CNT;
210 }
211 restore_flags(flags);
212 DEB(printk(", scb is %x",scbptr);)
213
214 if (i >= OGMB_CNT) {
215 DEB(printk(", no free OGMBs.\n");)
216
217 return 0;
218 }
219
220 wd7000_enable_intr();
221 do {
222 WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
223 outb(START_OGMB|ogmb, COMMAND);
224 WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
225 } while (inb(ASC_STAT) & CMD_REJ);
226
227 DEB(printk(", awaiting interrupt.\n");)
228 return 1;
229
230 fail:
231 DEB(printk(", WAIT timed out.\n");)
232 return 0;
233 }
234
235
236 int make_code(unsigned hosterr, unsigned scsierr)
237 {
238 #ifdef DEBUG
239 int in_error = hosterr;
240 #endif
241
242 switch ((hosterr>>8)&0xff){
243 case 0:
244 hosterr = DID_ERROR;
245 break;
246 case 1:
247 hosterr = DID_OK;
248 break;
249 case 2:
250 hosterr = DID_OK;
251 break;
252 case 4:
253 hosterr = DID_TIME_OUT;
254 break;
255 case 5:
256 hosterr = DID_RESET;
257 break;
258 case 6:
259 hosterr = DID_BAD_TARGET;
260 break;
261 case 80:
262 case 81:
263 hosterr = DID_BAD_INTR;
264 break;
265 case 82:
266 hosterr = DID_ABORT;
267 break;
268 case 83:
269 case 84:
270 hosterr = DID_RESET;
271 break;
272 default:
273 hosterr = DID_ERROR;
274 break;
275 }
276 #ifdef DEBUG
277 if (scsierr||hosterr)
278 printk("\nSCSI command error: SCSI %02x host %04x return %d",
279 scsierr,in_error,hosterr);
280 #endif
281 return scsierr | (hosterr << 16);
282 }
283
284
285 static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
286 {
287 DEB(printk("wd7000_scsi_done: %06x\n",SCpnt);)
288 SCpnt->SCp.phase = 0;
289 }
290
291
292 void wd7000_intr_handle(int irq)
293 {
294 int flag, icmb, errstatus, icmb_status;
295 int host_error, scsi_error;
296 Scb *scb;
297 unchar *icb;
298 Scsi_Cmnd *SCpnt;
299
300 flag = inb(INTR_STAT);
301 DEB(printk("wd7000_intr_handle: intr stat = %02x",flag);)
302
303 if (!(inb(ASC_STAT)&0x80)){
304 DEB(printk("\nwd7000_intr_handle: phantom interrupt...\n");)
305 wd7000_intr_ack();
306 return;
307 }
308
309
310 if ((flag & 0x40) == 0) {
311
312 DEB(printk("wd7000_intr_handle: free outgoing mailbox\n");)
313 wd7000_intr_ack();
314 return;
315 }
316
317 icmb = flag & 0x3f;
318 scb = (struct scb *) scsi2int(mb.icmb[icmb].scbptr);
319 icmb_status = mb.icmb[icmb].status;
320 mb.icmb[icmb].status = 0;
321
322 #ifdef DEBUG
323 printk(" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x",
324 icmb, scb, icmb_status, scb->vue );
325 #endif
326
327 if (!(scb->op & 0x80)) {
328 SCpnt = scb->SCpnt;
329 if (--(SCpnt->SCp.phase) <= 0) {
330 host_error = scb->vue | (icmb_status << 8);
331 scsi_error = scb->status;
332 errstatus = make_code(host_error,scsi_error);
333 SCpnt->result = errstatus;
334
335 if (SCpnt->host_scribble != NULL)
336 scsi_free(SCpnt->host_scribble,WD7000_SCRIBBLE);
337 free_scb(scb);
338
339 SCpnt->scsi_done(SCpnt);
340 }
341 } else {
342 icb = (unchar *) scb;
343 icb[ICB_STATUS] = icmb_status;
344 icb[ICB_PHASE] = 0;
345 }
346
347 wd7000_intr_ack();
348 DEB(printk(".\n");)
349 return;
350 }
351
352
353 int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
354 {
355 Scb *scb;
356 Sgb *sgb;
357 unchar *cdb;
358 unchar idlun;
359 short cdblen;
360
361 cdb = (unchar *) SCpnt->cmnd;
362 cdblen = COMMAND_SIZE(*cdb);
363 idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
364 SCpnt->scsi_done = done;
365 SCpnt->SCp.phase = 1;
366 scb = alloc_scb();
367 scb->idlun = idlun;
368 memcpy(scb->cdb, cdb, cdblen);
369 scb->direc = 0x40;
370 scb->SCpnt = SCpnt;
371 SCpnt->host_scribble = NULL;
372 DEB(printk("request_bufflen is %x, bufflen is %x\n",\
373 SCpnt->request_bufflen, SCpnt->bufflen);)
374
375 if (SCpnt->use_sg) {
376 struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
377 unsigned i;
378
379 if (scsi_hosts[wd7000_host].sg_tablesize <= 0) {
380 panic("wd7000_queuecommand: scatter/gather not supported.\n");
381 }
382 #ifdef DEBUG
383 printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);
384 #endif
385
386
387
388
389 #ifdef DEBUG
390 if (SCpnt->use_sg > WD7000_SG)
391 panic("WD7000: requesting too many scatterblocks\n");
392 #endif
393 SCpnt->host_scribble = (unsigned char *) scsi_malloc(WD7000_SCRIBBLE);
394 sgb = (Sgb *) SCpnt->host_scribble;
395 if (sgb == NULL)
396 panic("wd7000_queuecommand: scsi_malloc() failed.\n");
397
398 scb->op = 1;
399 any2scsi(scb->dataptr, sgb);
400 any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );
401
402 for (i = 0; i < SCpnt->use_sg; i++) {
403 any2scsi(sgb->ptr, sg[i].address);
404 any2scsi(sgb->len, sg[i].length);
405 sgb++;
406 }
407 DEB(printk("Using %d bytes for %d scatter/gather blocks\n",\
408 scsi2int(scb->maxlen), SCpnt->use_sg);)
409 } else {
410 scb->op = 0;
411 any2scsi(scb->dataptr, SCpnt->request_buffer);
412 any2scsi(scb->maxlen, SCpnt->request_bufflen);
413 }
414
415 return mail_out(scb);
416 }
417
418
419 int wd7000_command(Scsi_Cmnd *SCpnt)
420 {
421 wd7000_queuecommand(SCpnt, wd7000_scsi_done);
422
423 while (SCpnt->SCp.phase > 0);
424
425 return SCpnt->result;
426 }
427
428
429 int wd7000_init(void)
430 { int i;
431 unchar init_block[] = {
432 INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT
433 };
434
435
436 outb(SCSI_RES|ASC_RES, CONTROL);
437 delay(1);
438 outb(0,CONTROL); controlstat = 0;
439
440
441
442
443
444
445
446
447 delay(200);
448
449 WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
450 DEB(printk("wd7000_init: Power-on Diagnostics finished\n");)
451 if (((i=inb(INTR_STAT)) != 1) && (i != 7)) {
452 panic("wd7000_init: Power-on Diagnostics error\n");
453 return 0;
454 }
455
456
457 memset(&mb,0,sizeof (mb));
458
459 init_scbs();
460
461
462 any2scsi(init_block+5,&mb);
463
464 if (!command_out(init_block,sizeof(init_block))) {
465 panic("WD-7000 Initialization failed.\n");
466 return 0;
467 }
468
469
470 WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
471 outb(DISABLE_UNS_INTR, COMMAND);
472 WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
473
474
475 if (request_irq(IRQ_LVL, wd7000_intr_handle)) {
476 panic("Unable to allocate IRQ for WD-7000.\n");
477 return 0;
478 };
479 if(request_dma(DMA_CH)) {
480 panic("Unable to allocate DMA channel for WD-7000.\n");
481 free_irq(IRQ_LVL);
482 return 0;
483 };
484 wd7000_enable_dma();
485 wd7000_enable_intr();
486
487 printk("WD-7000 initialized.\n");
488 return 1;
489 fail:
490 return 0;
491 }
492
493
494 void wd7000_revision(void)
495 {
496 volatile unchar icb[ICB_LEN] = {0x8c};
497
498 icb[ICB_PHASE] = 1;
499 mail_out( (struct scb *) icb );
500 while (icb[ICB_PHASE]) ;
501 rev_1 = icb[1];
502 rev_2 = icb[2];
503
504
505
506
507 if (rev_1 >= 7) scsi_hosts[wd7000_host].sg_tablesize = WD7000_SG;
508 }
509
510
511 static const char *wd_bases[] = {(char *)0xce000,(char *)0xd8000};
512
513 typedef struct {
514 char * signature;
515 unsigned offset;
516 unsigned length;
517 } Signature;
518
519 static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}};
520
521 #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
522
523
524 int wd7000_detect(int hostnum)
525
526
527
528 {
529 int i,j;
530 char const *base_address = NULL;
531
532 if(check_region(IO_BASE, 4)) return 0;
533 for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
534 for(j=0;j<NUM_SIGNATURES;j++){
535 if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
536 (void *) signatures[j].signature,signatures[j].length)){
537 base_address=wd_bases[i];
538 printk("WD-7000 detected.\n");
539 }
540 }
541 }
542 if (base_address == NULL) return 0;
543
544 snarf_region(IO_BASE, 4);
545
546 wd7000_host = hostnum;
547
548 wd7000_init();
549 wd7000_revision();
550
551 return 1;
552 }
553
554
555
556 static void wd7000_append_info( char *info, const char *fmt, ... )
557
558
559
560 {
561 va_list args;
562 extern int vsprintf(char *buf, const char *fmt, va_list args);
563
564 va_start(args, fmt);
565 vsprintf(info, fmt, args);
566 va_end(args);
567
568 return;
569 }
570
571
572 const char *wd7000_info(void)
573 {
574 static char info[80] = "Western Digital WD-7000, Firmware Revision ";
575
576 wd7000_revision();
577 wd7000_append_info( info+strlen(info), "%d.%d.\n", rev_1, rev_2 );
578
579 return info;
580 }
581
582 int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
583 {
584 #ifdef DEBUG
585 printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);
586 printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
587 { int j; unchar *cdbj = (unchar *) SCpnt->cmnd;
588 for (j=0; j < COMMAND_SIZE(*cdbj); j++) printk(" %02x", *(cdbj++));
589 printk(" result %08x\n", SCpnt->result);
590 }
591 #endif
592 return 0;
593 }
594
595
596
597
598
599
600 int wd7000_reset(Scsi_Cmnd * SCpnt)
601 {
602 #ifdef DEBUG
603 printk("wd7000_reset\n");
604 #endif
605 if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
606 return 0;
607 }
608
609
610 int wd7000_biosparam(int size, int dev, int* ip)
611
612
613
614
615 {
616 ip[0] = 64;
617 ip[1] = 32;
618 ip[2] = size >> 11;
619
620 return 0;
621 }
622