xref: /haiku/src/add-ons/kernel/busses/scsi/53c8xx/53c8xx.c (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2 	Copyright 1998-1999, Be Incorporated.   All Rights Reserved.
3 	This file may be used under the terms of the Be Sample Code License.
4 */
5 
6 /*
7 ** 53c8xx.c - Symbios 53c8xx SIM
8 */
9 
10 #define DEBUG_SYMBIOS  1   /* Print Debugging Messages */
11 #define DEBUG_ISR      0   /* messages in ISR... leave off */
12 #define DEBUG_PM       0   /* messages when Phase Mismatch occurs... leave off */
13 #define DEBUG_SAFETY   0   /* don't load driver if serial debug off */
14 
15 #define USE_STATFS     0
16 
17 /*
18 ** Debugging Macros
19 */
20 #if DEBUG_SYMBIOS
21 #define d_printf dprintf
22 #else
23 #define d_printf(x...)
24 #endif
25 
26 #include <OS.h>
27 #include <KernelExport.h>
28 #include <PCI.h>
29 #include <CAM.h>
30 #include <ByteOrder.h>
31 
32 /* shorthand byteswapping macros */
33 #define LE(n) B_HOST_TO_LENDIAN_INT32(n)
34 #define HE(n) B_LENDIAN_TO_HOST_INT32(n)
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 
40 #include <string.h>
41 #include <iovec.h>
42 
43 #include "53c8xx.h"
44 
45 #include "symbios.h"
46 
47 #if USE_STATFS
48 #include <stat_module.h>
49 
50 static int32
51 stat_controller(void *stats, char **buf)
52 {
53 	Symbios *s = (Symbios *) stats;
54 
55 	if(*buf = (char *) malloc(256)){
56 		sprintf(*buf,
57 				"Chipset:   %s\n"
58 				"IO Base:   0x%08x\n"
59 				"SRAM Base: 0x%08x\n"
60 				"IRQ Line:  %d\n"
61 				"SCSI Bus:  %s\n",
62 				s->name, s->iobase, s->sram_phys, s->irq,
63 				s->max_targ_id > 7 ? "Wide" : "Narrow");
64 		return strlen(*buf);
65 	} else {
66 		return 0;
67 	}
68 }
69 
70 static int32
71 stat_target(void *stats, char **buf)
72 {
73 	SymTarg *st = (SymTarg *) stats;
74 
75 	if(st->flags & tf_ignore){
76 		*buf = NULL;
77 		return 0;
78 	}
79 
80 	if(*buf = (char *) malloc(256)){
81 		if(st->offset){
82 			sprintf(*buf,
83 					"Width:     %s\n"
84 					"Transfer:  Sync\n"
85 					"Period:    %d ns\n"
86 					"Offset:    %d\n",
87 					st->wide ? "Wide" : "Narrow",
88 					st->period,
89 					st->offset
90 					);
91 		} else {
92 			sprintf(*buf,
93 					"Width:     %s\n"
94 					"Transfer:  Async\n",
95 					st->wide ? "Wide" : "Narrow");
96 		}
97 		return strlen(*buf);
98 	} else {
99 		return 0;
100 	}
101 }
102 
103 
104 static void register_stats(Symbios *s)
105 {
106 	char buf[128];
107 	stat_module_info_t *stats;
108 	int i;
109 
110 	if(s->registered) return;
111 
112 	if(get_module("generic/stat_module", (module_info**) &stats) == B_OK){
113 		sprintf(buf,"scsi/53c8xx/%d/info",s->num);
114 		stats->register_statistics(buf, s, stat_controller);
115 		for(i=0;i<=s->max_targ_id;i++){
116 			sprintf(buf,"scsi/53c8xx/%d/targ_%x",s->num,i);
117 			stats->register_statistics(buf, &(s->targ[i]), stat_target);
118 		}
119 		s->registered = 1;
120 	} else {
121 		dprintf("symbios: cannot find stats module...\n");
122 	}
123 }
124 
125 #else
126 #define register_stats(x)
127 
128 #endif
129 
130 /*
131 ** Constants for the SIM
132 */
133 #define SIM_VERSION 0x01
134 #define HBA_VERSION 0x01
135 
136 static char sim_vendor_name[]   = "Be, Inc.";
137 static char hba_vendor_name[]   = "Symbios";
138 
139 static pci_module_info		*pci;
140 static cam_for_sim_module_info	*cam;
141 
142 static char	cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
143 static char	pci_name[] = B_PCI_MODULE_NAME;
144 
145 /*
146 ** Supported Device / Device Attributes table
147 */
148 #define symf_sram       0x0001      /* on board SCRIPTS ram */
149 #define symf_doubler    0x0002      /* SCLK doubler available */
150 #define symf_quadrupler 0x0004      /* SCLK quadrupler available */
151 #define symf_untested   0x1000      /* never actually tested one of these */
152 #define symf_wide       0x0008      /* supports WIDE bus */
153 #define symf_short      0x0010      /* short max period (8) */
154 
155 static struct {
156 	uint32 id;
157 	uint32 rev;
158 	char *name;
159 	int flags;
160 } devinfo[] = {
161 	{ 0x0001, 0x10, "53c810a", symf_short },
162 	{ 0x0001, 0x00, "53c810",  symf_short },
163 	{ 0x0006, 0x00, "53c860",  symf_wide | symf_short | symf_untested },
164 	{ 0x0004, 0x00, "53c815",  symf_short | symf_untested },
165 	{ 0x0002, 0x00, "53c820",  symf_wide | symf_short | symf_untested },
166 	{ 0x0003, 0x10, "53c825a", symf_wide | symf_short |symf_sram | symf_untested },
167 	{ 0x0003, 0x00, "53c825",  symf_wide | symf_short | symf_untested },
168 	{ 0x000f, 0x02, "53c875",  symf_wide | symf_sram | symf_doubler },
169 	{ 0x000f, 0x00, "53c875",  symf_wide | symf_sram },
170 	{ 0x008f, 0x00, "53c875j", symf_wide | symf_sram | symf_doubler },
171 	{ 0x000d, 0x00, "53c885",  symf_wide | symf_sram | symf_untested },
172 	{ 0x000c, 0x00, "53c895",  symf_wide | symf_sram | symf_quadrupler | symf_untested },
173 	{ 0x000b, 0x00, "53c896",  symf_wide | symf_sram | symf_untested },
174 	{ 0, 0, NULL, 0 }
175 };
176 
177 #include "scripts.c"
178 
179 static void
180 setparams(SymTarg *t, uint period, uint offset, uint wide)
181 {
182 	Symbios *s = t->adapter;
183 
184 	if(wide){
185 		if(!t->wide) kprintf("symbios%ld: target %ld wide\n",s->num,t->id);
186 		t->wide = 1;
187 	} else {
188 		t->wide = 0;
189 	}
190 
191 	if(period){
192 		int i;
193 		for(i=0;i<s->syncsize;i++){
194 			if(period <= s->syncinfo[i].period){
195 				t->period = s->syncinfo[i].period;
196 				t->offset = offset;
197 
198 				t->device[3] = s->syncinfo[i].scntl3;
199 				if(t->wide) t->device[3] |= 0x08;
200 				t->device[2] = t->id;
201 				t->device[1] = s->syncinfo[i].sxfer | (offset & 0x0f);
202 				t->device[0] = 0;
203 				kprintf("symbios%ld: target %ld sync period=%ld, offset=%d\n",
204 						s->num, t->id, t->period, offset);
205 				return;
206 			}
207 		}
208 	}
209 
210 	t->period = 0;
211 	t->offset = 0;
212 
213 	t->device[3] = s->scntl3; /* scntl3 - clock divisor */
214 	if(t->wide) t->device[3] |= 0x08;
215 	t->device[2] = t->id;     /* dest id */
216 	t->device[1] = 0;         /* sync xfer */
217 	t->device[0] = 0;         /* reserved */
218 }
219 
220 static long init_symbios(Symbios *s, int restarting);
221 
222 /*
223 ** IO Macros
224 */
225 
226 /* XXX - fix me bjs */
227 #define inb(p)     (*pci->read_io_8)(s->iobase + p)
228 #define outb(p,v)  (*pci->write_io_8)(s->iobase + p,v)
229 #define inw(p)     (*pci->read_io_16)(s->iobase + p)
230 #define outw(p,v)  (*pci->write_io_16)(s->iobase + p,v)
231 #define in32(p)    (*pci->read_io_32)(s->iobase + p)
232 #define out32(p,v) (*pci->write_io_32)(s->iobase + p,v)
233 
234 
235 /* patch in an external symbol */
236 #define RESOLV(sname,value) \
237 { int i; \
238 	d_printf("symbios%d: relocting %d instances of %s to 0x%08x\n", \
239 			 s->num,sizeof(E_##sname##_Used)/4,#sname,value); \
240 	for(i=0;i<(sizeof(E_##sname##_Used)/4);i++) { \
241 		scr[E_##sname##_Used[i]] = ((uint32) value); \
242 	} \
243 }
244 
245 /* calc phys addr of a ptr inside the sram area */
246 #define PHADDR(lvar) ((s->sram_phys) + (((uint32) &(lvar)) - ((uint32) s->script)))
247 
248 /* calc phys addr of a ptr inside the priv area */
249 /*#define PPHADDR(ptr) (st->priv_phys + (((uint32) ptr) - ((uint32) st->priv)))*/
250 #define PPHADDR(ptr) (phys + (((uint32) ptr) - ((uint32) sp)))
251 
252 /* prepare a Targ's scripts indirect table for one or more exec_io's */
253 static void prep_io(SymPriv *sp, uint32 phys)
254 {
255 	sp->syncmsg.address = LE(PPHADDR(sp->_syncmsg));
256 	sp->syncmsg.count = LE(3);
257 
258 	sp->widemsg.address = LE(PPHADDR(sp->_widemsg));
259 	sp->widemsg.count = LE(2);
260 
261 	sp->sendmsg.address = LE(PPHADDR(sp->_sendmsg));
262 
263 	sp->recvmsg.address = LE(PPHADDR(sp->_recvmsg));
264 	sp->recvmsg.count = LE(1);
265 
266 	sp->status.address = LE(PPHADDR(sp->_status));
267 	sp->status.count = LE(1);
268 
269 	sp->extdmsg.address = LE(PPHADDR(sp->_extdmsg));
270 	sp->extdmsg.count = LE(1);
271 
272 	sp->command.address = LE(PPHADDR(sp->_command));
273 }
274 
275 /*
276  * actually execute an io transaction via SCRIPTS
277  * you MUST hold st->sem_targ before calling this
278  *
279  */
280 static void exec_io(SymTarg *st, void *cmd, int cmdlen, void *msg, int msglen,
281 				   void *data, int datalen, int sg)
282 {
283 	cpu_status former;
284 	Symbios *s = st->adapter;
285 
286 	memcpy((void *) &(st->priv->device.count), st->device, 4);
287 
288 	st->priv->sendmsg.count = LE(msglen);
289 	memcpy(st->priv->_sendmsg, msg, msglen);
290 	st->priv->command.count = LE(cmdlen);
291 	memcpy(st->priv->_command, cmd, cmdlen);
292 
293 	st->table_phys = st->priv_phys + ADJUST_PRIV_TO_TABLE;
294 
295 	if(datalen){
296 		int i,sgcount;
297 		uint32 opcode;
298 		SymInd *t = st->priv->table;
299 		physical_entry *pe = (physical_entry *) &(st->priv->table[1]);
300 
301 		if(st->inbound){
302 			opcode = s->op_in;
303 			st->datain_phys = st->table_phys;
304 			st->dataout_phys = s->sram_phys + Ent_phase_dataerr;
305 		} else {
306 			opcode = s->op_out;
307 			st->dataout_phys = st->table_phys;
308 			st->datain_phys = s->sram_phys + Ent_phase_dataerr;
309 		}
310 
311 		if(sg) {
312 			iovec *vec = (iovec *) data;
313 			for(sgcount=0,i=0;i<datalen;i++){
314 				get_memory_map(vec[i].iov_base, vec[i].iov_len, &pe[sgcount], 130-sgcount);
315 				while(pe[sgcount].size && (sgcount < 130)){
316 					t[sgcount].address = LE((uint32) pe[sgcount].address);
317 					t[sgcount].count = LE(opcode | pe[sgcount].size);
318 					sgcount++;
319 				}
320 				if((sgcount == 130) && pe[sgcount].size){
321 					panic("symbios: sg list overrun");
322 				}
323 			}
324 		} else {
325 			get_memory_map(data, datalen, pe, 130);
326 			for(i=0;pe[i].size;i++){
327 				t[i].address = LE((uint32) pe[i].address);
328 				t[i].count = LE(opcode | pe[i].size);
329 			}
330 			sgcount = i;
331 		}
332 		t[sgcount].count = LE(OP_END);
333 		t[sgcount].address = LE(ARG_END);
334 
335 //		for(i=0;i<=sgcount;i++){
336 //			dprintf("sym: %04d - %08x %08x\n",i,t[i].address,t[i].count);
337 //		}
338 	} else {
339 		st->datain_phys = s->sram_phys + Ent_phase_dataerr;
340 		st->dataout_phys = s->sram_phys + Ent_phase_dataerr;
341 	}
342 
343 //	dprintf("sym: pp = %08x  di = %08x  do = %08x\n",st->priv_phys,st->datain_phys,st->dataout_phys);
344 
345 	st->status = status_queued;
346 
347 /*	dprintf("symbios: enqueueing %02x %02x %02x ... for %d (%d bytes %s)\n",
348 			((uchar *)cmd)[0],((uchar *)cmd)[1],((uchar *)cmd)[2],
349 			st->device[2],datalen,st->inbound?"IN":"OUT");
350 */
351 	former = disable_interrupts();
352 	acquire_spinlock(&(s->hwlock));
353 
354 	/* enqueue the request */
355 	if(s->startqueuetail){
356 		s->startqueuetail->next = st;
357 	} else {
358 		s->startqueue = st;
359 	}
360 	st->next = NULL;
361 	s->startqueuetail = st;
362 
363 	/* If the adapter is idle, signal it so that this request may be started */
364 	if(s->status == IDLE) outb(sym_istat, sym_istat_sigp);
365 
366 	release_spinlock(&(s->hwlock));
367 	restore_interrupts(former);
368 
369 	/* wait for completion */
370 	acquire_sem(st->sem_done);
371 
372 #if 0
373 	if(acquire_sem_etc(st->sem_done, 1, B_TIMEOUT, 10*1000000) != B_OK){
374 		kprintf("sym: targ %d never finished,  argh...\n",st->device[2]);
375 		init_symbios(st->adapter,1);
376 		st->state = sTIMEOUT;
377 		return;
378 	}
379 #endif
380 }
381 
382 
383 #if DEBUG_ISR
384 #define kp kprintf
385 #else
386 #define kp(x...)
387 #endif
388 
389 static int32
390 scsi_int_dispatch(void *data)
391 {
392 	Symbios *s = (Symbios *) data;
393 	int reselected = 0;
394 	uchar istat;
395 
396 	if(s->reset) return B_UNHANDLED_INTERRUPT;
397 
398 	acquire_spinlock(&(s->hwlock));
399 	istat = inb(sym_istat);
400 
401 	if(istat & sym_istat_dip){
402 		uchar dstat = inb(sym_dstat);
403 
404 		if(dstat & sym_dstat_sir){
405 			/* Handle and interrupt from the SCRIPTS program */
406 		 	uint32 status = HE(in32(sym_dsps));
407 	//		kprintf("<%02x>",status);
408 
409 			switch(status){
410 			case status_ready:
411 				kp("sym: ready\n");
412 				break;
413 
414 			case status_iocomplete:
415 				kp("sym: done %08x\n",s->active);
416 				if(s->active){
417 					/* io is complete -- any more io is an error */
418 					s->active->datain_phys = s->sram_phys + Ent_phase_dataerr;
419 					s->active->dataout_phys = s->sram_phys + Ent_phase_dataerr;
420 				}
421 				break;
422 
423 			case status_reselected:{
424 				uint32 id = inb(sym_ssid);
425 				if(id & sym_ssid_val) {
426 					s->active = &(s->targ[id & s->idmask]);
427 					kp("sym: resel %08x\n",s->active);
428 					if(s->active->status != status_waiting){
429 						s->active = NULL;
430 						kprintf("symbios: bad reselect %ld\n",id & sym_ssid_encid);
431 					} else {
432 						reselected = 1;
433 					}
434 				} else {
435 					kprintf("symbios: invalid reselection!?\n");
436 				}
437 				break;
438 			}
439 
440 			case status_timeout:
441 				/* inform the unlucky party and dequeue it */
442 				kp("sym: timeout %08lx\n",s->startqueue);
443 				if(s->startqueue){
444 					s->startqueue->status = status_timeout;
445 					release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE);
446 					if(!(s->startqueue = s->startqueue->next)){
447 						s->startqueuetail = NULL;
448 					}
449 				}
450 				break;
451 
452 			case status_selected:
453 				/* selection succeeded.  Remove from start queue and make active */
454 				kp("sym: selected %08lx\n",s->startqueue);
455 				if(s->startqueue){
456 					s->active = s->startqueue;
457 					s->active->status = status_active;
458 					if(!(s->startqueue = s->startqueue->next)){
459 						s->startqueuetail = NULL;
460 					}
461 				}
462 				break;
463 
464 			case status_syncin:
465 				setparams(s->active,
466 						  s->active->priv->_syncmsg[1]*4,
467 						  s->active->priv->_syncmsg[2],
468 						  s->active->wide);
469 				break;
470 
471 			case status_widein:
472 				setparams(s->active, s->active->period, s->active->offset,
473 						  s->active->priv->_widemsg[1]);
474 				break;
475 
476 			case status_ignore_residue:
477 				kprintf("ignore residue 0x%02x\n",s->active->priv->_extdmsg[0]);
478 				break;
479 
480 			case status_disconnect:
481 				kp("sym: disc %08lx\n",s->active);
482 				/* device disconnected. make inactive */
483 				if(s->active){
484 					s->active->status = status_waiting;
485 					s->active = NULL;
486 				}
487 				break;
488 
489 			case status_badmsg:
490 				kp("sym: badmsg %02x\n",s->active->priv->_recvmsg[0]);
491 
492 			case status_complete:
493 			case status_badstatus:
494 			case status_overrun:
495 			case status_underrun:
496 			case status_badphase:
497 			case status_badextmsg:
498 				kp("sym: error %08lx / %02x\n",s->active,status);
499 				/* transaction completed successfully or in error. report our status. */
500 				if(s->active){
501 					s->active->status = status;
502 					release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE);
503 					s->active = NULL;
504 				}
505 				break;
506 
507 			case status_selftest:
508 				/* signal a response to the selftest ... don't actually start up the
509 				   SCRIPTS like we normally do */
510 				s->status = OFFLINE;
511 				goto done;
512 				break;
513 
514 			default:
515 				kp("sym: int 0x%08lx ...\n",status);
516 			}
517 			goto reschedule;
518 		} else {
519 			kprintf("symbios: weird error, dstat = %02x\n",dstat);
520 		}
521 	}
522 
523 	if(istat & sym_istat_sip){
524 		uchar sist0;
525 		sist0 = inb(sym_sist1);
526 
527 		if(sist0 & sym_sist1_sbmc){
528 			kprintf("sym: SBMC %02x!\n",inb(sym_stest4) & 0xc0);
529 		}
530 
531 		if(sist0 & sym_sist1_sto){
532 			/* select timeout */
533 			kp("sym: Timeout %08lx\n",s->startqueue);
534 			/* inform the unlucky party and dequeue it */
535 			if(s->startqueue){
536 				s->startqueue->status = status_timeout;
537 				release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE);
538 				if(!(s->startqueue = s->startqueue->next)){
539 					s->startqueuetail = NULL;
540 				}
541 			} else {
542 				kprintf("symbios: ghost target timed out\n");
543 			}
544 			inb(sym_sist0);	//   apparently we MUST read sist0 as well
545 			goto reschedule;
546 		}
547 
548 		sist0 = inb(sym_sist0) & 0x8f;
549 
550 		if(sist0 && s->active){
551 			if(sist0 & sym_sist0_ma){
552 				/* phase mismatch -- we experienced a disconnect while in
553 				   a DataIn or DataOut... gotta figure out how much we
554 				   transferred, update the sgtable, take the FIFOs into
555 				   account, etc (see 9-9 in Symbios PCI-SCSI Programming Guide) */
556 				SymInd *t;
557 				uint32 dfifo_val, bytesleft, dbc;
558 				uint32 dsp = HE(in32(sym_dsp));
559 				uint32 n = (dsp - s->active->table_phys) / 8 - 1;
560 
561 				if((dsp < s->active->priv_phys) || (n > 129)) {
562 					/* we mismatched during some other phase ?! */
563 					kprintf("Phase Mismatch (dsp = 0x%08lx)\n",dsp);
564 					goto reschedule;
565 				}
566 
567 				t = &(s->active->priv->table[n]);
568 
569 #if 0
570 				t->count = HE(t->count);
571 				t->address = HE(t->count);
572 #endif
573 				/* dbc initially = table[n].count, counts down */
574 				dbc = (uint32) HE(in32(sym_dbc)) & 0x00ffffffL;
575 
576 				t->count &= 0xffffff;
577 #if DEBUG_PM
578 				kprintf("PM(%s) dbc=0x%08x, n=%02d, a=0x%08x, l=0x%08x\n",
579 						s->active->inbound ? " in" : "out", dbc, n, t->address, t->count);
580 #endif
581 				if(s->active->inbound){
582 					/* data in is easy... flush happens automatically */
583 					t->address += t->count - dbc;
584 					t->count = dbc;
585 #if DEBUG_PM
586 					kprintf("                              a=0x%08x, l=0x%08x\n",
587 					t->address, t->count);
588 #endif
589 					s->active->datain_phys = s->active->table_phys + 8*(t->count ? n : n+1);
590 					t->count |= s->op_in;
591 #if 0
592 					t->count = LE(t->count);
593 					t->address = LE(t->address);
594 #endif
595 					goto reschedule;
596 				} else {
597 					if(inb(sym_ctest5) & 0x20){
598 						/* wide FIFO */
599 						dfifo_val = ((inb(sym_ctest5) & 0x03) << 8) | inb(sym_dfifo);
600 						bytesleft = (dfifo_val - (dbc & 0x3ff)) & 0x3ff;
601 					} else {
602 						dfifo_val = (inb(sym_dfifo) & 0x7f);
603 						bytesleft = (dfifo_val - (dbc & 0x7f)) & 0x7f;
604 					}
605 					if(inb(sym_sstat0) & 0x20) bytesleft++;
606 					if(inb(sym_sstat2) & 0x20) bytesleft++;
607 					if(inb(sym_sstat0) & 0x40) bytesleft++;
608 					if(inb(sym_sstat2) & 0x40) bytesleft++;
609 
610 					/* clear fifo */
611 					outb(sym_ctest3, 0x04);
612 
613 					t->address += t->count - dbc;
614 					t->count = dbc;
615 
616 					/* adjust for data that didn't make it to the target */
617 					t->address -= bytesleft;
618 					t->count += bytesleft;
619 #if DEBUG_PM
620 					kprintf("                              a=0x%08x, l=0x%08x\n",
621 					t->address, t->count);
622 #endif
623 					s->active->dataout_phys = s->active->table_phys + 8*(t->count ? n : n+1);
624 					t->count |= s->op_out;
625 #if 0
626 					t->count = LE(t->count);
627 					t->address = LE(t->address);
628 #endif
629 					spin(10);
630 					goto reschedule;
631 				}
632 			}
633 
634 			if(sist0 & sym_sist0_udc){
635 				kprintf("symbios: Unexpected Disconnect (dsp = 0x%08lx)\n", in32(sym_dsp));
636 			}
637 
638 			if(sist0 & sym_sist0_sge){
639 				kprintf("symbios: SCSI Gross Error\n");
640 			}
641 
642 			if(sist0 & sym_sist0_rst){
643 				kprintf("symbios: SCSI Reset\n");
644 			}
645 
646 			if(sist0 & sym_sist0_par){
647 				kprintf("symbios: Parity Error\n");
648 			}
649 
650 			s->active->status = status_badphase;
651 			release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE);
652 			s->active = NULL;
653 
654 			goto reschedule;
655 		}
656 	} else {
657 		/* nothing happened... must be somebody else's problem */
658 		release_spinlock(&(s->hwlock));
659 		 return B_UNHANDLED_INTERRUPT;
660 	}
661 
662 reschedule:
663 	/* start the SCRIPTS processor at one of three places, depending on state
664 	**
665 	** 1. If there is an active transaction, insure that the script is patched
666 	**    correctly, the DSA is loaded, and start up at "switch".
667 	**
668 	** 2. If there is a transaction at the head of the startqueue, set the DSA
669 	**    and start up at "start" to try to select the target and start the
670 	**    transaction
671 	**
672 	** 3. If there is nothing else to do, go to "idle" and wait for signal or
673 	**    reselection
674 	*/
675 
676 	if(s->active){
677 		out32(sym_dsa, s->active->priv_phys + ADJUST_PRIV_TO_DSA);
678 		s->script[PATCH_DATAIN] = LE(s->active->datain_phys);
679 		s->script[PATCH_DATAOUT] = LE(s->active->dataout_phys);
680 
681 		s->active->status = status_active;
682 		s->status = ACTIVE;
683 		if(reselected){
684 			out32(sym_dsp, LE(s->sram_phys + Ent_switch_resel));
685 			//kp("sym: restart @ %08x / reselected\n",Ent_switch_resel);
686 		} else {
687 			out32(sym_dsp, LE(s->sram_phys + Ent_switch));
688 			//kp("sym: restart @ %08x / selected\n", Ent_switch);
689 		}
690 	} else {
691 		if(s->startqueue){
692 			out32(sym_dsa, LE(s->startqueue->priv_phys + ADJUST_PRIV_TO_DSA));
693 
694 			s->startqueue->status = status_selecting;
695 			s->status = START;
696 			out32(sym_dsp, LE(s->sram_phys + Ent_start));
697 			//kp("sym: restart @ %08x / started\n", Ent_start);
698 		} else {
699 			s->status = IDLE;
700 			out32(sym_dsp, LE(s->sram_phys + Ent_idle));
701 			//kp("sym: restart @ %08x / idle\n", Ent_idle);
702 		}
703 	}
704 
705 done:
706 	release_spinlock(&(s->hwlock));
707     return B_HANDLED_INTERRUPT;
708 }
709 
710 
711 /* init the adapter... if restarting, no bus reset or whathaveyou */
712 static long init_symbios(Symbios *s, int restarting)
713 {
714     d_printf("symbios%ld: init_symbios()\n",s->num);
715 
716 	if(restarting){
717 		s->reset = 1;
718 	} else {
719 		s->reset = 0;
720 	}
721 
722 	if(!restarting){
723 		/* reset the SCSI bus */
724 		dprintf("symbios%ld: scsi bus reset\n",s->num);
725 		outb(sym_scntl1, sym_scntl1_rst);
726 		spin(25);
727 		outb(sym_scntl1, 0);
728 		spin(250000);
729 
730 		/* clear ints */
731 		inb(sym_istat);
732 		inb(sym_sist0);
733 		inb(sym_sist1);
734 		inb(sym_dstat);
735 
736 		install_io_interrupt_handler(s->irq, scsi_int_dispatch, s, 0);
737 		d_printf("symbios%ld: registered interrupt handler for irq %ld\n",s->num,s->irq);
738 	}
739 
740 	/* enable irqs, prefetch, no 53c700 compat */
741 	outb(sym_dcntl, sym_dcntl_com);
742 
743 	/* enable all DMA ints */
744 	outb(sym_dien, sym_dien_sir | sym_dien_mdpe | sym_dien_bf | sym_dien_abrt
745 		 | sym_dien_iid);
746 	/* enable all fatal SCSI ints */
747 	outb(sym_sien0, sym_sien0_ma | sym_sien0_sge | sym_sien0_udc | sym_sien0_rst |
748 		 sym_sien0_par);
749 	outb(sym_sien1, sym_sien1_sto | sym_sien1_sbmc); // XXX
750 
751 	/* sel / hth timeouts */
752 	outb(sym_stime0, 0xbb);
753 
754 	/* clear ints */
755 	inb(sym_istat);
756 	inb(sym_sist0);
757 	inb(sym_sist1);
758 	inb(sym_dstat);
759 
760 	/* clear ints */
761 	inb(sym_sist0);
762 	inb(sym_sist1);
763 	inb(sym_dstat);
764 
765 	if(restarting){
766 		s->reset = 0;
767 	} else {
768 		int i;
769 		s->status = TEST;
770 
771 		dprintf("symbios%ld: selftest ",s->num);
772 		out32(sym_dsp, LE(s->sram_phys + Ent_test));
773 		for(i=0;(s->status == TEST) && i<10;i++) {
774 			dprintf(".");
775 			spin(10000);
776 		}
777 		if(s->status == TEST){
778 			dprintf("FAIL\n");
779 			return B_ERROR; //XXX teardown
780 		} else {
781 			dprintf("PASS\n");
782 		}
783 	}
784 
785 	s->status = IDLE;
786 	out32(sym_dsp, LE(s->sram_phys + Ent_idle));
787     d_printf("symbios%ld: started script\n",s->num);
788 
789     return B_NO_ERROR;
790 }
791 
792 /* When an inquiry succeeds the negotiator gets the option to attempt to
793 ** request a better transfer agreement with the target.
794 */
795 static void negotiator(Symbios *s, SymTarg *targ, uchar *ident, uchar *msg)
796 {
797 	if(ident[7] & 0x20){ /* wide supported */
798 		if(targ->flags & tf_ask_wide){
799 			uchar cmd[6] = { 0, 0, 0, 0, 0, 0 };
800 			targ->flags &= (~tf_ask_wide); /* only ask once */
801 
802 			dprintf("symbios%ld: negotiating wide xfer with target %ld\n",
803 			s->num,targ->id);
804 
805 			msg[1] = 0x01; /* extended message */
806 			msg[2] = 0x02; /* length           */
807 			msg[3] = 0x03; /* sync negotiate   */
808 			msg[4] = 0x01; /* 16 bit wide      */
809 
810 			exec_io(targ, cmd, 6, msg, 5, NULL, 0, 0);
811 		}
812 	}
813 
814 	if(ident[7] & 0x10){ /* sync supported */
815 		if(targ->flags & tf_ask_sync) {
816 			uchar cmd[6] = { 0, 0, 0, 0, 0, 0 };
817 
818 			targ->flags &= (~tf_ask_sync); /* only ask once */
819 
820 			dprintf("symbios%ld: negotiating sync xfer with target %ld\n",
821 			s->num,targ->id);
822 
823 			msg[1] = 0x01; /* extended message */
824 			msg[2] = 0x03; /* length           */
825 			msg[3] = 0x01; /* sync negotiate   */
826 			msg[4] = s->syncinfo[0].period / 4; /* sync period / 4  */
827 			msg[5] = s->maxoffset;
828 
829 			exec_io(targ, cmd, 6, msg, 6, NULL, 0, 0);
830 		}
831 	}
832 }
833 
834 /* Convert a CCB_SCSIIO into a BL_CCB32 and (possibly SG array).
835 **
836 */
837 static long sim_execute_scsi_io(Symbios *s, CCB_HEADER *ccbh)
838 {
839 	CCB_SCSIIO *ccb = (CCB_SCSIIO *) ccbh;
840 	uchar *cdb;
841 	physical_entry pe[2];
842 	SymTarg *targ;
843 	uchar msg[8];
844 
845 	targ = s->targ + ccb->cam_ch.cam_target_id;
846 
847 	if(targ->flags & tf_ignore){
848 		ccbh->cam_status = CAM_SEL_TIMEOUT;
849 		return B_OK;
850 	}
851 
852 	if(ccb->cam_ch.cam_flags & CAM_CDB_POINTER) {
853 		cdb = ccb->cam_cdb_io.cam_cdb_ptr;
854 	} else {
855 		cdb = ccb->cam_cdb_io.cam_cdb_bytes;
856 	}
857 
858 	get_memory_map((void*) (ccb->cam_sim_priv), 1536, pe, 2);
859 
860 	/* identify message */
861 	msg[0] = 0xC0 | (ccb->cam_ch.cam_target_lun & 0x07);
862 
863 	/* fill out table */
864 	prep_io((SymPriv *) ccb->cam_sim_priv, (uint32) pe[0].address);
865 
866 	/* insure only one transaction at a time for any given target */
867 	acquire_sem(targ->sem_targ);
868 
869 	targ->priv = (SymPriv *) ccb->cam_sim_priv;;
870 	targ->priv_phys = (uint32 ) pe[0].address;
871 
872 	targ->inbound = (ccb->cam_ch.cam_flags & CAM_DIR_IN) ? 1 : 0;
873 
874 	if(ccb->cam_ch.cam_flags & CAM_SCATTER_VALID){
875 		exec_io(targ, cdb, ccb->cam_cdb_len, msg, 1,
876 				ccb->cam_data_ptr, ccb->cam_sglist_cnt, 1);
877 	} else {
878 		exec_io(targ, cdb, ccb->cam_cdb_len, msg, 1,
879 				ccb->cam_data_ptr, ccb->cam_dxfer_len, 0);
880 	}
881 
882 /*	dprintf("symbios%d: state = 0x%02x, status = 0x%02x\n",
883 			s->num,targ->state,targ->priv->status[0]);*/
884 
885 	/* decode status */
886 	switch(targ->status){
887 	case status_complete:
888 		if((ccb->cam_scsi_status=targ->priv->_status[0]) != 0) {
889 			ccbh->cam_status = CAM_REQ_CMP_ERR;
890 
891 			/* nonzero status is an error ... 0x02 = check condition */
892 			if((ccb->cam_scsi_status == 0x02) &&
893 			   !(ccb->cam_ch.cam_flags & CAM_DIS_AUTOSENSE) &&
894 			   ccb->cam_sense_ptr && ccb->cam_sense_len){
895 				   uchar command[6];
896 
897 				   command[0] = 0x03;		/* request_sense */
898 				   command[1] = ccb->cam_ch.cam_target_lun << 5;
899 				   command[2] = 0;
900 				   command[3] = 0;
901 				   command[4] = ccb->cam_sense_len;
902 				   command[5] = 0;
903 
904 				   targ->inbound = 1;
905 				   exec_io(targ, command, 6, msg, 1,
906 						   ccb->cam_sense_ptr, ccb->cam_sense_len, 0);
907 
908 				   if(targ->priv->_status[0]){
909 					   ccb->cam_ch.cam_status |= CAM_AUTOSENSE_FAIL;
910 				   } else {
911 					   ccb->cam_ch.cam_status |= CAM_AUTOSNS_VALID;
912 				   }
913 			}
914 		} else {
915 			ccbh->cam_status = CAM_REQ_CMP;
916 
917 			if(cdb[0] == 0x12) {
918 				/* inquiry just succeeded ... is it non SG and with enough data to
919 				   snoop the support bits? */
920 				if(!(ccb->cam_ch.cam_flags & CAM_SCATTER_VALID) && (ccb->cam_dxfer_len>7)){
921 					negotiator(s, targ, ccb->cam_data_ptr, msg);
922 				}
923 			}
924 		}
925 		break;
926 
927 	case status_timeout:
928 		ccbh->cam_status = CAM_SEL_TIMEOUT;
929 		break;
930 
931 	default: // XXX
932 		ccbh->cam_status = CAM_SEL_TIMEOUT;
933 	}
934 
935 	targ->status = status_inactive;
936 //	dprintf("symbios%d: releasing targ @ 0x%08x\n",s->num,targ);
937 	release_sem(targ->sem_targ);
938 	return B_OK;
939 }
940 
941 /*
942 ** sim_path_inquiry returns info on the target/lun.
943 */
944 static long sim_path_inquiry(Symbios *s, CCB_HEADER *ccbh)
945 {
946     CCB_PATHINQ	*ccb;
947     ccb = (CCB_PATHINQ *) ccbh;
948     ccb->cam_version_num = SIM_VERSION;
949     ccb->cam_target_sprt = 0;
950     ccb->cam_hba_eng_cnt = 0;
951     memset (ccb->cam_vuhba_flags, 0, VUHBA);
952     ccb->cam_sim_priv = SIM_PRIV;
953     ccb->cam_async_flags = 0;
954     ccb->cam_initiator_id = s->host_targ_id;
955 	ccb->cam_hba_inquiry = s->max_targ_id > 7 ? PI_WIDE_16 : 0 ;
956     strncpy (ccb->cam_sim_vid, sim_vendor_name, SIM_ID);
957     strncpy (ccb->cam_hba_vid, hba_vendor_name, HBA_ID);
958     ccb->cam_osd_usage = 0;
959     ccbh->cam_status = CAM_REQ_CMP;
960 	register_stats(s);
961     return 0;
962 }
963 
964 
965 /*
966 ** sim_extended_path_inquiry returns info on the target/lun.
967 */
968 static long sim_extended_path_inquiry(Symbios *s, CCB_HEADER *ccbh)
969 {
970     CCB_EXTENDED_PATHINQ *ccb;
971 
972     sim_path_inquiry(s, ccbh);
973     ccb = (CCB_EXTENDED_PATHINQ *) ccbh;
974     sprintf(ccb->cam_sim_version, "%d.0", SIM_VERSION);
975     sprintf(ccb->cam_hba_version, "%d.0", HBA_VERSION);
976     strncpy(ccb->cam_controller_family, "Symbios", FAM_ID);
977     strncpy(ccb->cam_controller_type, s->name, TYPE_ID);
978     return 0;
979 }
980 
981 /*
982 ** scsi_sim_action performes the scsi i/o command embedded in the
983 ** passed ccb.
984 **
985 ** The target/lun ids are assumed to be in range.
986 */
987 static long sim_action(Symbios *s, CCB_HEADER *ccbh)
988 {
989 	ccbh->cam_status = CAM_REQ_INPROG;
990 	switch(ccbh->cam_func_code){
991 	case XPT_SCSI_IO:
992 		return sim_execute_scsi_io(s,ccbh);
993 	case XPT_PATH_INQ:
994 		return sim_path_inquiry(s,ccbh);
995 	case XPT_EXTENDED_PATH_INQ:
996 		return sim_extended_path_inquiry(s, ccbh);
997 	default:
998 		ccbh->cam_status = CAM_REQ_INVALID;
999 		return -1;
1000 	}
1001 }
1002 
1003 static void reloc_script(Symbios *s)
1004 {
1005 	int i;
1006 	ulong *scr = s->script;
1007 
1008 	memcpy(scr, SCRIPT, sizeof(SCRIPT));
1009 	for(i=0;i<PATCHES;i++){
1010 		scr[LABELPATCHES[i]] += s->sram_phys;
1011 	}
1012 	d_printf("symbios%ld: loaded %ld byte SCRIPT, relocated %ld labels\n",
1013 			 s->num, sizeof(SCRIPT), PATCHES);
1014 
1015 		/* disable scsi ints */
1016 	outb(sym_scratcha, 0x42);
1017 	outb(sym_scratcha+1, 0x00);
1018 	outb(sym_scratchb, 0x04);
1019 	outb(sym_sien0, 0);
1020 	outb(sym_sien1, 0);
1021 	outb(sym_dien, sym_dien_sir);
1022 
1023 	/* clear ints */
1024 	inb(sym_sist0);
1025 	inb(sym_sist1);
1026 	inb(sym_dstat);
1027 
1028 	outb(sym_dmode, ( sym_dmode_diom | sym_dmode_siom, 0 ));	/* FIXME: ??? */
1029 }
1030 
1031 static uint32 sym_readclock(Symbios *s)
1032 {
1033 	uint32 ms,a,i;
1034 	bigtime_t t0,t1;
1035 
1036 	outw(sym_sien0 , 0);    /* mask all scsi interrupts        */
1037 	outb(sym_dien , 0);     /* mask all dma interrupts         */
1038 	inw(sym_sist0);         /* clear pending scsi interrupts   */
1039 	outb(sym_scntl3, 4);    /* set pre-scaler to divide by 3   */
1040 
1041 	for(a=0,i=0;i<5;i++){
1042 		ms = 0;
1043 		outb(sym_stime1, 0);    /* disable general purpose timer   */
1044 		spin(10000);            /* let it all settle for 10ms      */
1045 		inw(sym_sist0);         /* another one, just to be sure :) */
1046 
1047 		t0 = system_time();
1048 		outb(sym_stime1, 11);   /* delay of 128ms */
1049 		while (!(inb(sym_sist1) & sym_sist1_gen)) snooze(250);
1050 		t1 = system_time();
1051 		ms = (t1-t0)/1000 + 10; /* we seem to be off by 10ms typically */
1052 
1053 		a += ((1 << 11) * 4400) / ms;
1054 	}
1055 
1056 	outb(sym_stime1, 0);    /* disable general purpose timer   */
1057 	return a / 5;
1058 }
1059 
1060 static uchar id_bits[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1061 
1062 /*
1063 ** Allocate the actual memory for the cardinfo object
1064 */
1065 static Symbios *create_cardinfo(int num, pci_info *pi, int flags)
1066 {
1067 	char name[32];
1068 	Symbios *s;
1069 	int i,scf;
1070 	area_id aid;
1071 	uint32 stest2,stest4;
1072 
1073 	if((pi->u.h0.interrupt_line == 0) || (pi->u.h0.interrupt_line > 128)) {
1074 		return NULL; /* invalid IRQ */
1075 	}
1076 
1077 	if(!(s = (Symbios *) malloc(sizeof(Symbios)))) return NULL;
1078 
1079 	s->num = num;
1080 	s->iobase = pi->u.h0.base_registers[0];
1081 	s->irq = pi->u.h0.interrupt_line;
1082 	s->hwlock = 0;
1083 	s->startqueue = NULL;
1084 	s->startqueuetail = NULL;
1085 	s->active = NULL;
1086 
1087 	sprintf(name,"sym%d:sram",num);
1088 	if(flags & symf_sram){
1089 		unsigned char *c;
1090 		s->sram_phys = pi->u.h0.base_registers[2];
1091 		if((aid=map_physical_memory(name, (void *) s->sram_phys, 4096,
1092 									 B_ANY_KERNEL_ADDRESS, B_READ_AREA + B_WRITE_AREA,
1093 									 (void **) &(s->script))) < 0){
1094 			free(s);
1095 			return NULL;
1096 		}
1097 		/* memory io test */
1098 		c = (unsigned char *) s->script;
1099 		for(i=0;i<4096;i++) c[i] = (255 - (i & 0xff));
1100 		for(i=0;i<4096;i++) {
1101 			if(c[i] != (255 - (i & 0xff))) {
1102 				d_printf("symbios%d: scripts ram io error @ %d\n",num,i);
1103 				goto err;
1104 			}
1105 		}
1106 	} else {
1107 		uchar *a;
1108 		physical_entry entries[2];
1109 		aid = create_area(name, (void **)&a, B_ANY_KERNEL_ADDRESS, 4096*5,
1110 		                  B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
1111 		if(aid == B_ERROR || aid == B_BAD_VALUE || aid == B_NO_MEMORY){
1112 			free(s);
1113 		    return NULL;
1114 		}
1115 		get_memory_map(a, 4096, entries, 2);
1116 		s->sram_phys = (uint32) entries[0].address;
1117 		s->script = (uint32 *) a;
1118 	}
1119 
1120 	d_printf("symbios%d: scripts ram @ 0x%08lx, mapped to 0x%08lx (%s)\n",
1121 			 num, s->sram_phys, (uint32) s->script,
1122 			 flags & symf_sram ? "onboard" : "offboard" );
1123 
1124 	/* what are we set at now? */
1125 	s->host_targ_id = inb(sym_scid) & 0x07;
1126 	dprintf("symbios%ld: host id %ld\n",s->num,s->host_targ_id);
1127 
1128 	s->host_targ_id = 7;  /* XXX figure this out somehow... */
1129 	s->max_targ_id = (flags & symf_wide) ? 15 : 7;
1130 
1131 	stest2 = inb(sym_stest2);
1132 	stest4 = inb(sym_stest4);
1133 
1134 	/* software reset */
1135 	outb(sym_istat, sym_istat_srst);
1136 	spin(10000);
1137 	outb(sym_istat, 0);
1138 	spin(10000);
1139 
1140 	/* initiator mode, full arbitration */
1141 	outb(sym_scntl0, sym_scntl0_arb0 | sym_scntl0_arb1);
1142 
1143 	outb(sym_scntl1, 0);
1144 	outb(sym_scntl2, 0);
1145 
1146 	/* initiator id=7, respond to reselection */
1147 	/* respond to reselect of id 7 */
1148 	outb(sym_respid, id_bits[s->host_targ_id]);
1149 	outb(sym_scid, sym_scid_rre | s->host_targ_id);
1150 
1151 	outb(sym_dmode, 0);
1152 
1153 	dprintf("symbios%ld: stest2 = 0x%02lx, stest4 = 0x%02lx\n",s->num,stest2,stest4);
1154 
1155 	/* no differential, no loopback, no hiz, no always-wide, no filter, no lowlevel */
1156 	outb(sym_stest2, 0); // save diff bit
1157 	outb(sym_stest3, 0);
1158 
1159 //	if(flags & symf_quadrupler){
1160 //		outb(sym_stest4, sym_stest4_lvd);
1161 //	}
1162 
1163 	outb(sym_stest1, 0);    /* make sure clock doubler is OFF  */
1164 
1165 	s->sclk = sym_readclock(s);
1166 	dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
1167 
1168 	if(flags & symf_doubler){
1169 		/* if we have a doubler and we don't already have an 80MHz clock */
1170 		if((s->sclk > 35000) && (s->sclk < 45000)){
1171 			dprintf("symbios%ld: enabling clock doubler...\n",s->num);
1172 			outb(sym_stest1, 0x08);  /* enable doubler */
1173 			spin(200);                /* wait 20us      */
1174 			outb(sym_stest3, 0xa0);  /* halt sclk, enable TolerANT*/
1175 			outb(sym_scntl3, 0x05);  /* SCLK/4         */
1176 			outb(sym_stest1, 0x0c);  /* engage doubler */
1177 			outb(sym_stest3, 0x80);  /* reenable sclk, leave TolerANT on  */
1178 
1179 			spin(3000);
1180 
1181 			s->sclk = sym_readclock(s);
1182 			dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
1183 		}
1184 	}
1185 	if(flags & symf_quadrupler){
1186 		if((s->sclk > 35000) && (s->sclk < 45000)){
1187 			dprintf("symbios%ld: enabling clock quadrupler...\n",s->num);
1188 			outb(sym_stest1, 0x08);  /* enable doubler */
1189 			spin(200);                /* wait 20us      */
1190 			outb(sym_stest3, 0xa0);  /* halt sclk, enable TolerANT*/
1191 			outb(sym_scntl3, 0x05);  /* SCLK/4         */
1192 			outb(sym_stest1, 0x0c);  /* engage doubler */
1193 			outb(sym_stest3, 0x80);  /* reenable sclk, leave TolerANT on  */
1194 
1195 			spin(3000);
1196 
1197 			s->sclk = sym_readclock(s);
1198 			dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
1199 			s->sclk = 160000;
1200 		}
1201 	}
1202 	outb(sym_stest3, 0x80);  /* leave TolerANT on  */
1203 
1204 	scf = 0;
1205 	/* set CCF / SCF according to specs */
1206 	if(s->sclk < 25010) {
1207 		dprintf("symbios%ld: unsupported clock frequency\n",s->num);
1208 		goto err;  //		s->scntl3 = 0x01;
1209 	} else if(s->sclk < 37510){
1210 		dprintf("symbios%ld: unsupported clock frequency\n",s->num);
1211 		goto err;  //		s->scntl3 = 0x02;
1212 	} else if(s->sclk < 50010){
1213 		/* 40MHz - divide by 1, 2 */
1214 		scf = 0x10;
1215 		s->scntl3 = 0x03;
1216 	} else if(s->sclk < 75010){
1217 		dprintf("symbios%ld: unsupported clock frequency\n",s->num);
1218 		goto err; //		s->scntl3 = 0x04;
1219 	} else if(s->sclk < 85000){
1220 		/* 80 MHz - divide by 2, 4*/
1221 		scf = 0x30;
1222 		s->scntl3 = 0x05;
1223 	} else {
1224 		/* 160 MHz - divide by 4, 8 */
1225 		scf = 0x50;
1226 		s->scntl3 = 0x07;
1227 	}
1228 
1229 
1230 	s->maxoffset = (flags & symf_short) ? 8 : 15 ;
1231 	s->syncsize = 0;
1232 
1233 	if(scf == 0x50){
1234 		/* calculate values for 160MHz clock */
1235 		for(i=0;i<4;i++){
1236 			s->syncinfo[s->syncsize].sxfer = i << 5;
1237 			s->syncinfo[s->syncsize].scntl3 = s->scntl3 | 0x90; /* /2, Ultra2 */
1238 			s->syncinfo[s->syncsize].period_ns = (625 * (i+4)) / 100;
1239 			s->syncinfo[s->syncsize].period = 4 * (s->syncinfo[s->syncsize].period_ns / 4);
1240 			s->syncsize++;
1241 		}
1242 	}
1243 
1244 	if(scf >= 0x30){
1245 		/* calculate values for 80MHz clock */
1246 		for(i=0;i<4;i++){
1247 			s->syncinfo[s->syncsize].sxfer = i << 5;
1248 			if(scf == 0x30){
1249 				s->syncinfo[s->syncsize].scntl3 = s->scntl3 | 0x90; /* /2, Ultra */
1250 			} else {
1251 				s->syncinfo[s->syncsize].scntl3 = s->scntl3 | 0xb0; /* /4, Ultra2 */
1252 			}
1253 
1254 			s->syncinfo[s->syncsize].period_ns = (125 * (i+4)) / 10;
1255 			s->syncinfo[s->syncsize].period = 4 * (s->syncinfo[s->syncsize].period_ns / 4);
1256 			s->syncsize++;
1257 		}
1258 	}
1259 
1260 	/* calculate values for 40MHz clock */
1261 	for(i=0;i<8;i++){
1262 		s->syncinfo[s->syncsize].sxfer = i << 5;
1263 		s->syncinfo[s->syncsize].scntl3 = s->scntl3 | scf;
1264 		s->syncinfo[s->syncsize].period_ns = 25 * (i+4);
1265 		s->syncinfo[s->syncsize].period = 4 * (s->syncinfo[s->syncsize].period_ns / 4);
1266 		s->syncsize++;
1267 	}
1268 
1269 	for(i=0;i<s->syncsize;i++){
1270 		dprintf("symbios%ld: syncinfo[%d] = { %02x, %02x, %d ns, %d ns }\n",
1271 				s->num, i,
1272 				s->syncinfo[i].sxfer, s->syncinfo[i].scntl3,
1273 				s->syncinfo[i].period_ns, s->syncinfo[i].period);
1274 	}
1275 
1276 	for(i=0;i<16;i++){
1277 		s->targ[i].id = i;
1278 		s->targ[i].adapter = s;
1279 		s->targ[i].wide = 0;
1280 		s->targ[i].offset = 0;
1281 		s->targ[i].status = status_inactive;
1282 
1283 		if((i == s->host_targ_id) || (i > s->max_targ_id)){
1284 			s->targ[i].flags = tf_ignore;
1285 		} else {
1286 			s->targ[i].flags = tf_ask_sync;
1287 			if(flags & symf_wide) s->targ[i].flags |= tf_ask_wide;
1288 //			s->targ[i].flags = 0;
1289 
1290 			setparams(s->targ + i, 0, 0, 0);
1291 
1292 			sprintf(name,"sym%ld:%02d:lock",s->num,i);
1293 			s->targ[i].sem_targ = create_sem(1,name);
1294 
1295 			sprintf(name,"sym%ld:%02d:done",s->num,i);
1296 			s->targ[i].sem_done = create_sem(0,name);
1297 		}
1298 	}
1299 
1300 	if(flags & symf_wide){
1301 		s->idmask = 15;
1302 		s->op_in = OP_WDATA_IN;
1303 		s->op_out = OP_WDATA_OUT;
1304 	} else {
1305 		s->idmask = 7;
1306 		s->op_in = OP_NDATA_IN;
1307 		s->op_out = OP_NDATA_OUT;
1308 	}
1309 
1310 	reloc_script(s);
1311     return s;
1312 
1313 err:
1314 	free(s);
1315 	delete_area(aid);
1316 	return NULL;
1317 }
1318 
1319 
1320 /*
1321 ** Multiple Card Cruft
1322 */
1323 #define MAXCARDS 4
1324 
1325 static Symbios *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
1326 
1327 static long sim_init0(void)                { return init_symbios(cardinfo[0],0); }
1328 static long sim_init1(void)                { return init_symbios(cardinfo[1],0); }
1329 static long sim_init2(void)                { return init_symbios(cardinfo[2],0); }
1330 static long sim_init3(void)                { return init_symbios(cardinfo[3],0); }
1331 static long sim_action0(CCB_HEADER *ccbh)  { return sim_action(cardinfo[0],ccbh); }
1332 static long sim_action1(CCB_HEADER *ccbh)  { return sim_action(cardinfo[1],ccbh); }
1333 static long sim_action2(CCB_HEADER *ccbh)  { return sim_action(cardinfo[2],ccbh); }
1334 static long sim_action3(CCB_HEADER *ccbh)  { return sim_action(cardinfo[3],ccbh); }
1335 
1336 static long (*sim_init_funcs[MAXCARDS])(void) = {
1337     sim_init0, sim_init1, sim_init2, sim_init3
1338 };
1339 
1340 static long (*sim_action_funcs[MAXCARDS])(CCB_HEADER *) = {
1341     sim_action0, sim_action1, sim_action2, sim_action3
1342 };
1343 
1344 
1345 /*
1346 ** Detect the controller and register the SIM with the CAM layer.
1347 ** returns the number of controllers installed...
1348 */
1349 static int
1350 sim_install_symbios(void)
1351 {
1352     int i, j, iobase, irq;
1353     int cardcount = 0;
1354     pci_info h;
1355     CAM_SIM_ENTRY entry;
1356 
1357     dprintf("symbios: sim_install()\n");
1358 
1359     for (i = 0; ; i++) {
1360 		if ((*pci->get_nth_pci_info) (i, &h) != B_NO_ERROR) {
1361 			/*if(!cardcount) d_printf("symbios: no controller found\n");*/
1362 			break;
1363 		}
1364 
1365 //		d_printf("scan: %04x %04x %02x\n", h.device_id, h.vendor_id, h.revision);
1366 
1367 #define PCI_VENDOR_SYMBIOS 0x1000
1368 
1369 		if(h.vendor_id == PCI_VENDOR_SYMBIOS) {
1370 			for(j=0;devinfo[j].id;j++){
1371 				if((devinfo[j].id == h.device_id) && (h.revision >= devinfo[j].rev)){
1372 					iobase = h.u.h0.base_registers[0];
1373 					irq = h.u.h0.interrupt_line;
1374 					d_printf("symbios%d: %s controller @ 0x%08x, irq %d\n",
1375 							 cardcount, devinfo[j].name, iobase, irq);
1376 
1377 					if(cardcount == MAXCARDS){
1378 						d_printf("symbios: too many controllers!\n");
1379 						return cardcount;
1380 					}
1381 
1382 					if((cardinfo[cardcount]=create_cardinfo(cardcount,&h,devinfo[j].flags)) != NULL){
1383 						cardinfo[cardcount]->name = devinfo[j].name;
1384 						entry.sim_init = sim_init_funcs[cardcount];
1385 						entry.sim_action = sim_action_funcs[cardcount];
1386 						cardinfo[cardcount]->registered = 0;
1387 						register_stats(cardinfo[cardcount]);
1388 
1389 						(*cam->xpt_bus_register)(&entry);
1390 						cardcount++;
1391 					} else {
1392 						d_printf("symbios%d: cannot allocate cardinfo\n",cardcount);
1393 					}
1394 					break;
1395 				}
1396 			}
1397 		}
1398     }
1399 
1400     return cardcount;
1401 }
1402 
1403 static status_t std_ops(int32 op, ...)
1404 {
1405 	switch(op) {
1406 	case B_MODULE_INIT:
1407 #if DEBUG_SAFETY
1408 		set_dprintf_enabled(true);
1409 #endif
1410 		load_driver_symbols("53c8xx");
1411 
1412 		if (get_module(pci_name, (module_info **) &pci) != B_OK)
1413 			return B_ERROR;
1414 
1415 		if (get_module(cam_name, (module_info **) &cam) != B_OK) {
1416 			put_module(pci_name);
1417 			return B_ERROR;
1418 		}
1419 
1420 		if(sim_install_symbios()){
1421 			return B_OK;
1422 		}
1423 
1424 		put_module(pci_name);
1425 		put_module(cam_name);
1426 		return B_ERROR;
1427 
1428 	case B_MODULE_UNINIT:
1429 		put_module(pci_name);
1430 		put_module(cam_name);
1431 		return B_OK;
1432 
1433 	default:
1434 		return B_ERROR;
1435 	}
1436 }
1437 
1438 static
1439 sim_module_info sim_symbios_module = {
1440 	{ "busses/scsi/53c8xx/v1", 0, &std_ops }
1441 };
1442 
1443 _EXPORT
1444 module_info  *modules[] =
1445 {
1446 	(module_info *) &sim_symbios_module,
1447 	NULL
1448 };
1449 
1450