xref: /haiku/src/add-ons/kernel/busses/scsi/53c8xx/53c8xx.c (revision 1a5860e2d20251067377524040a4f87e813f63d9)
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 
51 static int32
stat_controller(void * stats,char ** buf)52 stat_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 
71 static int32
stat_target(void * stats,char ** buf)72 stat_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 
register_stats(Symbios * s)105 static 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 
137 static char sim_vendor_name[]   = "Be, Inc.";
138 static char hba_vendor_name[]   = "Symbios";
139 
140 static pci_module_info		*pci;
141 static cam_for_sim_module_info	*cam;
142 
143 static char	cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
144 static 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 
156 static 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 
180 static void
setparams(SymTarg * t,uint period,uint offset,uint wide)181 setparams(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 
221 static 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 */
prep_io(SymPriv * sp,uint32 phys)254 static 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  */
exec_io(SymTarg * st,void * cmd,int cmdlen,void * msg,int msglen,void * data,int datalen,int sg)281 static 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 
390 static int32
scsi_int_dispatch(void * data)391 scsi_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 
663 reschedule:
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 
706 done:
707 	release_spinlock(&(s->hwlock));
708     return B_HANDLED_INTERRUPT;
709 }
710 
711 
712 /* init the adapter... if restarting, no bus reset or whathaveyou */
init_symbios(Symbios * s,int restarting)713 static 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 */
negotiator(Symbios * s,SymTarg * targ,uchar * ident,uchar * msg)796 static 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 */
sim_execute_scsi_io(Symbios * s,CCB_HEADER * ccbh)838 static 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 */
sim_path_inquiry(Symbios * s,CCB_HEADER * ccbh)945 static 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 */
sim_extended_path_inquiry(Symbios * s,CCB_HEADER * ccbh)969 static 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 */
sim_action(Symbios * s,CCB_HEADER * ccbh)988 static 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 
reloc_script(Symbios * s)1004 static 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 
sym_readclock(Symbios * s)1032 static 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 
1061 static uchar id_bits[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1062 
1063 /*
1064 ** Allocate the actual memory for the cardinfo object
1065 */
create_cardinfo(int num,pci_info * pi,int flags)1066 static 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 
1314 err:
1315 	free(s);
1316 	delete_area(aid);
1317 	return NULL;
1318 }
1319 
1320 
1321 /*
1322 ** Multiple Card Cruft
1323 */
1324 #define MAXCARDS 4
1325 
1326 static Symbios *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
1327 
sim_init0(void)1328 static long sim_init0(void)                { return init_symbios(cardinfo[0],0); }
sim_init1(void)1329 static long sim_init1(void)                { return init_symbios(cardinfo[1],0); }
sim_init2(void)1330 static long sim_init2(void)                { return init_symbios(cardinfo[2],0); }
sim_init3(void)1331 static long sim_init3(void)                { return init_symbios(cardinfo[3],0); }
sim_action0(CCB_HEADER * ccbh)1332 static long sim_action0(CCB_HEADER *ccbh)  { return sim_action(cardinfo[0],ccbh); }
sim_action1(CCB_HEADER * ccbh)1333 static long sim_action1(CCB_HEADER *ccbh)  { return sim_action(cardinfo[1],ccbh); }
sim_action2(CCB_HEADER * ccbh)1334 static long sim_action2(CCB_HEADER *ccbh)  { return sim_action(cardinfo[2],ccbh); }
sim_action3(CCB_HEADER * ccbh)1335 static long sim_action3(CCB_HEADER *ccbh)  { return sim_action(cardinfo[3],ccbh); }
1336 
1337 static long (*sim_init_funcs[MAXCARDS])(void) = {
1338     sim_init0, sim_init1, sim_init2, sim_init3
1339 };
1340 
1341 static 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 */
1350 static int
sim_install_symbios(void)1351 sim_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 
std_ops(int32 op,...)1404 static 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 
1437 static
1438 sim_module_info sim_symbios_module = {
1439 	{ "busses/scsi/53c8xx/v1", 0, &std_ops }
1440 };
1441 
1442 _EXPORT
1443 module_info  *modules[] =
1444 {
1445 	(module_info *) &sim_symbios_module,
1446 	NULL
1447 };
1448 
1449