btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / add-ons / kernel / busses / scsi / 53c8xx / 53c8xx.c
blob9eb4ac3b19de6b48d35597204d8a4c2ee4832070
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 */
6 /*
7 ** 53c8xx.c - Symbios 53c8xx SIM
8 */
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 */
15 #define USE_STATFS 0
18 ** Debugging Macros
20 #if DEBUG_SYMBIOS
21 #define d_printf dprintf
22 #else
23 #define d_printf(x...)
24 #endif
26 #include <module.h>
27 #include <OS.h>
28 #include <KernelExport.h>
29 #include <PCI.h>
30 #include <CAM.h>
31 #include <ByteOrder.h>
33 /* shorthand byteswapping macros */
34 #define LE(n) B_HOST_TO_LENDIAN_INT32(n)
35 #define HE(n) B_LENDIAN_TO_HOST_INT32(n)
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <stdarg.h>
41 #include <string.h>
42 #include <iovec.h>
44 #include "53c8xx.h"
46 #include "symbios.h"
48 #if USE_STATFS
49 #include <stat_module.h>
51 static int32
52 stat_controller(void *stats, char **buf)
54 Symbios *s = (Symbios *) stats;
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;
71 static int32
72 stat_target(void *stats, char **buf)
74 SymTarg *st = (SymTarg *) stats;
76 if(st->flags & tf_ignore){
77 *buf = NULL;
78 return 0;
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
92 } else {
93 sprintf(*buf,
94 "Width: %s\n"
95 "Transfer: Async\n",
96 st->wide ? "Wide" : "Narrow");
98 return strlen(*buf);
99 } else {
100 return 0;
105 static void register_stats(Symbios *s)
107 char buf[128];
108 stat_module_info_t *stats;
109 int i;
111 if(s->registered) return;
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);
120 s->registered = 1;
121 } else {
122 dprintf("symbios: cannot find stats module...\n");
126 #else
127 #define register_stats(x)
129 #endif
132 ** Constants for the SIM
134 #define SIM_VERSION 0x01
135 #define HBA_VERSION 0x01
137 static char sim_vendor_name[] = "Be, Inc.";
138 static char hba_vendor_name[] = "Symbios";
140 static pci_module_info *pci;
141 static cam_for_sim_module_info *cam;
143 static char cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
144 static char pci_name[] = B_PCI_MODULE_NAME;
147 ** Supported Device / Device Attributes table
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) */
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 }
178 #include "scripts.c"
180 static void
181 setparams(SymTarg *t, uint period, uint offset, uint wide)
183 Symbios *s = t->adapter;
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;
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;
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;
211 t->period = 0;
212 t->offset = 0;
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 */
221 static long init_symbios(Symbios *s, int restarting);
224 ** IO Macros
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)
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); \
246 /* calc phys addr of a ptr inside the sram area */
247 #define PHADDR(lvar) ((s->sram_phys) + (((uint32) &(lvar)) - ((uint32) s->script)))
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)))
253 /* prepare a Targ's scripts indirect table for one or more exec_io's */
254 static void prep_io(SymPriv *sp, uint32 phys)
256 sp->syncmsg.address = LE(PPHADDR(sp->_syncmsg));
257 sp->syncmsg.count = LE(3);
259 sp->widemsg.address = LE(PPHADDR(sp->_widemsg));
260 sp->widemsg.count = LE(2);
262 sp->sendmsg.address = LE(PPHADDR(sp->_sendmsg));
264 sp->recvmsg.address = LE(PPHADDR(sp->_recvmsg));
265 sp->recvmsg.count = LE(1);
267 sp->status.address = LE(PPHADDR(sp->_status));
268 sp->status.count = LE(1);
270 sp->extdmsg.address = LE(PPHADDR(sp->_extdmsg));
271 sp->extdmsg.count = LE(1);
273 sp->command.address = LE(PPHADDR(sp->_command));
277 * actually execute an io transaction via SCRIPTS
278 * you MUST hold st->sem_targ before calling this
281 static void exec_io(SymTarg *st, void *cmd, int cmdlen, void *msg, int msglen,
282 void *data, int datalen, int sg)
284 cpu_status former;
285 Symbios *s = st->adapter;
287 memcpy((void *) &(st->priv->device.count), st->device, 4);
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);
294 st->table_phys = st->priv_phys + ADJUST_PRIV_TO_TABLE;
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]);
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;
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++;
321 if((sgcount == 130) && pe[sgcount].size){
322 panic("symbios: sg list overrun");
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);
331 sgcount = i;
333 t[sgcount].count = LE(OP_END);
334 t[sgcount].address = LE(ARG_END);
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;
344 // dprintf("sym: pp = %08x di = %08x do = %08x\n",st->priv_phys,st->datain_phys,st->dataout_phys);
346 st->status = status_queued;
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");
352 former = disable_interrupts();
353 acquire_spinlock(&(s->hwlock));
355 /* enqueue the request */
356 if(s->startqueuetail){
357 s->startqueuetail->next = st;
358 } else {
359 s->startqueue = st;
361 st->next = NULL;
362 s->startqueuetail = st;
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);
367 release_spinlock(&(s->hwlock));
368 restore_interrupts(former);
370 /* wait for completion */
371 acquire_sem(st->sem_done);
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;
380 #endif
384 #if DEBUG_ISR
385 #define kp kprintf
386 #else
387 #define kp(x...)
388 #endif
390 static int32
391 scsi_int_dispatch(void *data)
393 Symbios *s = (Symbios *) data;
394 int reselected = 0;
395 uchar istat;
397 if(s->reset) return B_UNHANDLED_INTERRUPT;
399 acquire_spinlock(&(s->hwlock));
400 istat = inb(sym_istat);
402 if(istat & sym_istat_dip){
403 uchar dstat = inb(sym_dstat);
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);
410 switch(status){
411 case status_ready:
412 kp("sym: ready\n");
413 break;
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;
422 break;
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;
435 } else {
436 kprintf("symbios: invalid reselection!?\n");
438 break;
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;
451 break;
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;
463 break;
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;
472 case status_widein:
473 setparams(s->active, s->active->period, s->active->offset,
474 s->active->priv->_widemsg[1]);
475 break;
477 case status_ignore_residue:
478 kprintf("ignore residue 0x%02x\n",s->active->priv->_extdmsg[0]);
479 break;
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;
488 break;
490 case status_badmsg:
491 kp("sym: badmsg %02x\n",s->active->priv->_recvmsg[0]);
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;
506 break;
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;
515 default:
516 kp("sym: int 0x%08lx ...\n",status);
518 goto reschedule;
519 } else {
520 kprintf("symbios: weird error, dstat = %02x\n",dstat);
524 if(istat & sym_istat_sip){
525 uchar sist0;
526 sist0 = inb(sym_sist1);
528 if(sist0 & sym_sist1_sbmc){
529 kprintf("sym: SBMC %02x!\n",inb(sym_stest4) & 0xc0);
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;
542 } else {
543 kprintf("symbios: ghost target timed out\n");
545 inb(sym_sist0); // apparently we MUST read sist0 as well
546 goto reschedule;
549 sist0 = inb(sym_sist0) & 0x8f;
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;
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;
568 t = &(s->active->priv->table[n]);
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;
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;
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++;
611 /* clear fifo */
612 outb(sym_ctest3, 0x04);
614 t->address += t->count - dbc;
615 t->count = dbc;
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;
635 if(sist0 & sym_sist0_udc){
636 kprintf("symbios: Unexpected Disconnect (dsp = 0x%08lx)\n", in32(sym_dsp));
639 if(sist0 & sym_sist0_sge){
640 kprintf("symbios: SCSI Gross Error\n");
643 if(sist0 & sym_sist0_rst){
644 kprintf("symbios: SCSI Reset\n");
647 if(sist0 & sym_sist0_par){
648 kprintf("symbios: Parity Error\n");
651 s->active->status = status_badphase;
652 release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE);
653 s->active = NULL;
655 goto reschedule;
657 } else {
658 /* nothing happened... must be somebody else's problem */
659 release_spinlock(&(s->hwlock));
660 return B_UNHANDLED_INTERRUPT;
663 reschedule:
664 /* start the SCRIPTS processor at one of three places, depending on state
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".
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
673 ** 3. If there is nothing else to do, go to "idle" and wait for signal or
674 ** reselection
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);
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);
691 } else {
692 if(s->startqueue){
693 out32(sym_dsa, LE(s->startqueue->priv_phys + ADJUST_PRIV_TO_DSA));
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);
706 done:
707 release_spinlock(&(s->hwlock));
708 return B_HANDLED_INTERRUPT;
712 /* init the adapter... if restarting, no bus reset or whathaveyou */
713 static long init_symbios(Symbios *s, int restarting)
715 d_printf("symbios%ld: init_symbios()\n",s->num);
717 if(restarting){
718 s->reset = 1;
719 } else {
720 s->reset = 0;
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);
731 /* clear ints */
732 inb(sym_istat);
733 inb(sym_sist0);
734 inb(sym_sist1);
735 inb(sym_dstat);
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);
741 /* enable irqs, prefetch, no 53c700 compat */
742 outb(sym_dcntl, sym_dcntl_com);
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
752 /* sel / hth timeouts */
753 outb(sym_stime0, 0xbb);
755 /* clear ints */
756 inb(sym_istat);
757 inb(sym_sist0);
758 inb(sym_sist1);
759 inb(sym_dstat);
761 /* clear ints */
762 inb(sym_sist0);
763 inb(sym_sist1);
764 inb(sym_dstat);
766 if(restarting){
767 s->reset = 0;
768 } else {
769 int i;
770 s->status = TEST;
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);
778 if(s->status == TEST){
779 dprintf("FAIL\n");
780 return B_ERROR; //XXX teardown
781 } else {
782 dprintf("PASS\n");
786 s->status = IDLE;
787 out32(sym_dsp, LE(s->sram_phys + Ent_idle));
788 d_printf("symbios%ld: started script\n",s->num);
790 return B_NO_ERROR;
793 /* When an inquiry succeeds the negotiator gets the option to attempt to
794 ** request a better transfer agreement with the target.
796 static void negotiator(Symbios *s, SymTarg *targ, uchar *ident, uchar *msg)
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 */
803 dprintf("symbios%ld: negotiating wide xfer with target %ld\n",
804 s->num,targ->id);
806 msg[1] = 0x01; /* extended message */
807 msg[2] = 0x02; /* length */
808 msg[3] = 0x03; /* sync negotiate */
809 msg[4] = 0x01; /* 16 bit wide */
811 exec_io(targ, cmd, 6, msg, 5, NULL, 0, 0);
815 if(ident[7] & 0x10){ /* sync supported */
816 if(targ->flags & tf_ask_sync) {
817 uchar cmd[6] = { 0, 0, 0, 0, 0, 0 };
819 targ->flags &= (~tf_ask_sync); /* only ask once */
821 dprintf("symbios%ld: negotiating sync xfer with target %ld\n",
822 s->num,targ->id);
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;
830 exec_io(targ, cmd, 6, msg, 6, NULL, 0, 0);
835 /* Convert a CCB_SCSIIO into a BL_CCB32 and (possibly SG array).
838 static long sim_execute_scsi_io(Symbios *s, CCB_HEADER *ccbh)
840 CCB_SCSIIO *ccb = (CCB_SCSIIO *) ccbh;
841 uchar *cdb;
842 physical_entry pe[2];
843 SymTarg *targ;
844 uchar msg[8];
846 targ = s->targ + ccb->cam_ch.cam_target_id;
848 if(targ->flags & tf_ignore){
849 ccbh->cam_status = CAM_SEL_TIMEOUT;
850 return B_OK;
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;
859 get_memory_map((void*) (ccb->cam_sim_priv), 1536, pe, 2);
861 /* identify message */
862 msg[0] = 0xC0 | (ccb->cam_ch.cam_target_lun & 0x07);
864 /* fill out table */
865 prep_io((SymPriv *) ccb->cam_sim_priv, (uint32) pe[0].address);
867 /* insure only one transaction at a time for any given target */
868 acquire_sem(targ->sem_targ);
870 targ->priv = (SymPriv *) ccb->cam_sim_priv;;
871 targ->priv_phys = (uint32 ) pe[0].address;
873 targ->inbound = (ccb->cam_ch.cam_flags & CAM_DIR_IN) ? 1 : 0;
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);
883 /* dprintf("symbios%d: state = 0x%02x, status = 0x%02x\n",
884 s->num,targ->state,targ->priv->status[0]);*/
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;
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];
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;
905 targ->inbound = 1;
906 exec_io(targ, command, 6, msg, 1,
907 ccb->cam_sense_ptr, ccb->cam_sense_len, 0);
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;
915 } else {
916 ccbh->cam_status = CAM_REQ_CMP;
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);
926 break;
928 case status_timeout:
929 ccbh->cam_status = CAM_SEL_TIMEOUT;
930 break;
932 default: // XXX
933 ccbh->cam_status = CAM_SEL_TIMEOUT;
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;
943 ** sim_path_inquiry returns info on the target/lun.
945 static long sim_path_inquiry(Symbios *s, CCB_HEADER *ccbh)
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;
967 ** sim_extended_path_inquiry returns info on the target/lun.
969 static long sim_extended_path_inquiry(Symbios *s, CCB_HEADER *ccbh)
971 CCB_EXTENDED_PATHINQ *ccb;
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;
983 ** scsi_sim_action performes the scsi i/o command embedded in the
984 ** passed ccb.
986 ** The target/lun ids are assumed to be in range.
988 static long sim_action(Symbios *s, CCB_HEADER *ccbh)
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;
1004 static void reloc_script(Symbios *s)
1006 int i;
1007 ulong *scr = s->script;
1009 memcpy(scr, SCRIPT, sizeof(SCRIPT));
1010 for(i=0;i<PATCHES;i++){
1011 scr[LABELPATCHES[i]] += s->sram_phys;
1013 d_printf("symbios%ld: loaded %ld byte SCRIPT, relocated %ld labels\n",
1014 s->num, sizeof(SCRIPT), PATCHES);
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);
1024 /* clear ints */
1025 inb(sym_sist0);
1026 inb(sym_sist1);
1027 inb(sym_dstat);
1029 outb(sym_dmode, /*( sym_dmode_diom | sym_dmode_siom, 0 )*/ 0); /* FIXME: ??? */
1032 static uint32 sym_readclock(Symbios *s)
1034 uint32 ms,a,i;
1035 bigtime_t t0,t1;
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 */
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 :) */
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 */
1054 a += ((1 << 11) * 4400) / ms;
1057 outb(sym_stime1, 0); /* disable general purpose timer */
1058 return a / 5;
1061 static uchar id_bits[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1064 ** Allocate the actual memory for the cardinfo object
1066 static Symbios *create_cardinfo(int num, pci_info *pi, int flags)
1068 char name[32];
1069 Symbios *s;
1070 int i,scf;
1071 area_id aid;
1072 uint32 stest2,stest4;
1074 if((pi->u.h0.interrupt_line == 0) || (pi->u.h0.interrupt_line > 128)) {
1075 return NULL; /* invalid IRQ */
1078 if(!(s = (Symbios *) malloc(sizeof(Symbios)))) return NULL;
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;
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;
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;
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;
1116 get_memory_map(a, 4096, entries, 2);
1117 s->sram_phys = (uint32) entries[0].address;
1118 s->script = (uint32 *) a;
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" );
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);
1129 s->host_targ_id = 7; /* XXX figure this out somehow... */
1130 s->max_targ_id = (flags & symf_wide) ? 15 : 7;
1132 stest2 = inb(sym_stest2);
1133 stest4 = inb(sym_stest4);
1135 /* software reset */
1136 outb(sym_istat, sym_istat_srst);
1137 spin(10000);
1138 outb(sym_istat, 0);
1139 spin(10000);
1141 /* initiator mode, full arbitration */
1142 outb(sym_scntl0, sym_scntl0_arb0 | sym_scntl0_arb1);
1144 outb(sym_scntl1, 0);
1145 outb(sym_scntl2, 0);
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);
1152 outb(sym_dmode, 0);
1154 dprintf("symbios%ld: stest2 = 0x%02lx, stest4 = 0x%02lx\n",s->num,stest2,stest4);
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);
1160 // if(flags & symf_quadrupler){
1161 // outb(sym_stest4, sym_stest4_lvd);
1162 // }
1164 outb(sym_stest1, 0); /* make sure clock doubler is OFF */
1166 s->sclk = sym_readclock(s);
1167 dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
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 */
1180 spin(3000);
1182 s->sclk = sym_readclock(s);
1183 dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
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 */
1196 spin(3000);
1198 s->sclk = sym_readclock(s);
1199 dprintf("symbios%ld: clock is %ldKHz\n",s->num,s->sclk);
1200 s->sclk = 160000;
1203 outb(sym_stest3, 0x80); /* leave TolerANT on */
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;
1231 s->maxoffset = (flags & symf_short) ? 8 : 15 ;
1232 s->syncsize = 0;
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++;
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 */
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++;
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++;
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);
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;
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;
1291 setparams(s->targ + i, 0, 0, 0);
1293 sprintf(name,"sym%ld:%02d:lock",s->num,i);
1294 s->targ[i].sem_targ = create_sem(1,name);
1296 sprintf(name,"sym%ld:%02d:done",s->num,i);
1297 s->targ[i].sem_done = create_sem(0,name);
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;
1311 reloc_script(s);
1312 return s;
1314 err:
1315 free(s);
1316 delete_area(aid);
1317 return NULL;
1322 ** Multiple Card Cruft
1324 #define MAXCARDS 4
1326 static Symbios *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
1328 static long sim_init0(void) { return init_symbios(cardinfo[0],0); }
1329 static long sim_init1(void) { return init_symbios(cardinfo[1],0); }
1330 static long sim_init2(void) { return init_symbios(cardinfo[2],0); }
1331 static long sim_init3(void) { return init_symbios(cardinfo[3],0); }
1332 static long sim_action0(CCB_HEADER *ccbh) { return sim_action(cardinfo[0],ccbh); }
1333 static long sim_action1(CCB_HEADER *ccbh) { return sim_action(cardinfo[1],ccbh); }
1334 static long sim_action2(CCB_HEADER *ccbh) { return sim_action(cardinfo[2],ccbh); }
1335 static long sim_action3(CCB_HEADER *ccbh) { return sim_action(cardinfo[3],ccbh); }
1337 static long (*sim_init_funcs[MAXCARDS])(void) = {
1338 sim_init0, sim_init1, sim_init2, sim_init3
1341 static long (*sim_action_funcs[MAXCARDS])(CCB_HEADER *) = {
1342 sim_action0, sim_action1, sim_action2, sim_action3
1347 ** Detect the controller and register the SIM with the CAM layer.
1348 ** returns the number of controllers installed...
1350 static int
1351 sim_install_symbios(void)
1353 int i, j, iobase, irq;
1354 int cardcount = 0;
1355 pci_info h;
1356 CAM_SIM_ENTRY entry;
1358 dprintf("symbios: sim_install()\n");
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;
1366 // d_printf("scan: %04x %04x %02x\n", h.device_id, h.vendor_id, h.revision);
1368 #define PCI_VENDOR_SYMBIOS 0x1000
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);
1378 if(cardcount == MAXCARDS){
1379 d_printf("symbios: too many controllers!\n");
1380 return cardcount;
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]);
1390 (*cam->xpt_bus_register)(&entry);
1391 cardcount++;
1392 } else {
1393 d_printf("symbios%d: cannot allocate cardinfo\n",cardcount);
1395 break;
1401 return cardcount;
1404 static status_t std_ops(int32 op, ...)
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;
1414 if (get_module(cam_name, (module_info **) &cam) != B_OK) {
1415 put_module(pci_name);
1416 return B_ERROR;
1419 if(sim_install_symbios()){
1420 return B_OK;
1423 put_module(pci_name);
1424 put_module(cam_name);
1425 return B_ERROR;
1427 case B_MODULE_UNINIT:
1428 put_module(pci_name);
1429 put_module(cam_name);
1430 return B_OK;
1432 default:
1433 return B_ERROR;
1437 static
1438 sim_module_info sim_symbios_module = {
1439 { "busses/scsi/53c8xx/v1", 0, &std_ops }
1442 _EXPORT
1443 module_info *modules[] =
1445 (module_info *) &sim_symbios_module,
1446 NULL