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