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
50static int32
51stat_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
70static int32
71stat_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
104static 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
136static char sim_vendor_name[]   = "Be, Inc.";
137static char hba_vendor_name[]   = "Symbios";
138
139static pci_module_info		*pci;
140static cam_for_sim_module_info	*cam;
141
142static char	cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
143static 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
155static 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
179static void
180setparams(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
220static 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 */
253static 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 */
280static 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
389static int32
390scsi_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
662reschedule:
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
705done:
706	release_spinlock(&(s->hwlock));
707    return B_HANDLED_INTERRUPT;
708}
709
710
711/* init the adapter... if restarting, no bus reset or whathaveyou */
712static 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*/
795static 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*/
837static 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*/
944static 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*/
968static 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*/
987static 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
1003static 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
1031static 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
1060static uchar id_bits[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1061
1062/*
1063** Allocate the actual memory for the cardinfo object
1064*/
1065static 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, 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_32_BIT_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
1313err:
1314	free(s);
1315	delete_area(aid);
1316	return NULL;
1317}
1318
1319
1320/*
1321** Multiple Card Cruft
1322*/
1323#define MAXCARDS 4
1324
1325static Symbios *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
1326
1327static long sim_init0(void)                { return init_symbios(cardinfo[0],0); }
1328static long sim_init1(void)                { return init_symbios(cardinfo[1],0); }
1329static long sim_init2(void)                { return init_symbios(cardinfo[2],0); }
1330static long sim_init3(void)                { return init_symbios(cardinfo[3],0); }
1331static long sim_action0(CCB_HEADER *ccbh)  { return sim_action(cardinfo[0],ccbh); }
1332static long sim_action1(CCB_HEADER *ccbh)  { return sim_action(cardinfo[1],ccbh); }
1333static long sim_action2(CCB_HEADER *ccbh)  { return sim_action(cardinfo[2],ccbh); }
1334static long sim_action3(CCB_HEADER *ccbh)  { return sim_action(cardinfo[3],ccbh); }
1335
1336static long (*sim_init_funcs[MAXCARDS])(void) = {
1337    sim_init0, sim_init1, sim_init2, sim_init3
1338};
1339
1340static 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*/
1349static int
1350sim_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
1403static 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
1438static
1439sim_module_info sim_symbios_module = {
1440	{ "busses/scsi/53c8xx/v1", 0, &std_ops }
1441};
1442
1443_EXPORT
1444module_info  *modules[] =
1445{
1446	(module_info *) &sim_symbios_module,
1447	NULL
1448};
1449
1450