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