2 Copyright 1998-1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
7 ** 53c8xx.c - Symbios 53c8xx SIM
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 */
21 #define d_printf dprintf
23 #define d_printf(x...)
28 #include <KernelExport.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)
49 #include <stat_module.h>
52 stat_controller(void *stats
, char **buf
)
54 Symbios
*s
= (Symbios
*) stats
;
56 if(*buf
= (char *) malloc(256)){
63 s
->name
, s
->iobase
, s
->sram_phys
, s
->irq
,
64 s
->max_targ_id
> 7 ? "Wide" : "Narrow");
72 stat_target(void *stats
, char **buf
)
74 SymTarg
*st
= (SymTarg
*) stats
;
76 if(st
->flags
& tf_ignore
){
81 if(*buf
= (char *) malloc(256)){
88 st
->wide
? "Wide" : "Narrow",
96 st
->wide
? "Wide" : "Narrow");
105 static void register_stats(Symbios
*s
)
108 stat_module_info_t
*stats
;
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
);
122 dprintf("symbios: cannot find stats module...\n");
127 #define register_stats(x)
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) */
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
},
181 setparams(SymTarg
*t
, uint period
, uint offset
, uint wide
)
183 Symbios
*s
= t
->adapter
;
186 if(!t
->wide
) kprintf("symbios%ld: target %ld wide\n",s
->num
,t
->id
);
194 for(i
=0;i
<s
->syncsize
;i
++){
195 if(period
<= s
->syncinfo
[i
].period
){
196 t
->period
= s
->syncinfo
[i
].period
;
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);
204 kprintf("symbios%ld: target %ld sync period=%ld, offset=%d\n",
205 s
->num
, t
->id
, t
->period
, offset
);
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
);
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) \
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
)
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
;
299 SymInd
*t
= st
->priv
->table
;
300 physical_entry
*pe
= (physical_entry
*) &(st
->priv
->table
[1]);
304 st
->datain_phys
= st
->table_phys
;
305 st
->dataout_phys
= s
->sram_phys
+ Ent_phase_dataerr
;
308 st
->dataout_phys
= st
->table_phys
;
309 st
->datain_phys
= s
->sram_phys
+ Ent_phase_dataerr
;
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
);
321 if((sgcount
== 130) && pe
[sgcount
].size
){
322 panic("symbios: sg list overrun");
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
);
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);
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
;
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
);
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
;
391 scsi_int_dispatch(void *data
)
393 Symbios
*s
= (Symbios
*) data
;
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);
415 case status_iocomplete
:
416 kp("sym: done %08x\n",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
;
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
){
431 kprintf("symbios: bad reselect %ld\n",id
& sym_ssid_encid
);
436 kprintf("symbios: invalid reselection!?\n");
442 /* inform the unlucky party and dequeue it */
443 kp("sym: timeout %08lx\n",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
;
453 case status_selected
:
454 /* selection succeeded. Remove from start queue and make active */
455 kp("sym: selected %08lx\n",s
->startqueue
);
457 s
->active
= s
->startqueue
;
458 s
->active
->status
= status_active
;
459 if(!(s
->startqueue
= s
->startqueue
->next
)){
460 s
->startqueuetail
= NULL
;
467 s
->active
->priv
->_syncmsg
[0]*4,
468 s
->active
->priv
->_syncmsg
[1],
473 setparams(s
->active
, s
->active
->period
, s
->active
->offset
,
474 s
->active
->priv
->_widemsg
[1]);
477 case status_ignore_residue
:
478 kprintf("ignore residue 0x%02x\n",s
->active
->priv
->_extdmsg
[0]);
481 case status_disconnect
:
482 kp("sym: disc %08lx\n",s
->active
);
483 /* device disconnected. make inactive */
485 s
->active
->status
= status_waiting
;
491 kp("sym: badmsg %02x\n",s
->active
->priv
->_recvmsg
[0]);
493 case status_complete
:
494 case status_badstatus
:
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. */
502 s
->active
->status
= status
;
503 release_sem_etc(s
->active
->sem_done
, 1, B_DO_NOT_RESCHEDULE
);
508 case status_selftest
:
509 /* signal a response to the selftest ... don't actually start up the
510 SCRIPTS like we normally do */
516 kp("sym: int 0x%08lx ...\n",status
);
520 kprintf("symbios: weird error, dstat = %02x\n",dstat
);
524 if(istat
& sym_istat_sip
){
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
){
534 kp("sym: Timeout %08lx\n",s
->startqueue
);
535 /* inform the unlucky party and dequeue it */
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
;
543 kprintf("symbios: ghost target timed out\n");
545 inb(sym_sist0
); // apparently we MUST read sist0 as well
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) */
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
);
568 t
= &(s
->active
->priv
->table
[n
]);
571 t
->count
= HE(t
->count
);
572 t
->address
= HE(t
->count
);
574 /* dbc initially = table[n].count, counts down */
575 dbc
= (uint32
) HE(in32(sym_dbc
)) & 0x00ffffffL
;
577 t
->count
&= 0xffffff;
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
);
582 if(s
->active
->inbound
){
583 /* data in is easy... flush happens automatically */
584 t
->address
+= t
->count
- dbc
;
587 kprintf(" a=0x%08x, l=0x%08x\n",
588 t
->address
, t
->count
);
590 s
->active
->datain_phys
= s
->active
->table_phys
+ 8*(t
->count
? n
: n
+1);
591 t
->count
|= s
->op_in
;
593 t
->count
= LE(t
->count
);
594 t
->address
= LE(t
->address
);
598 if(inb(sym_ctest5
) & 0x20){
600 dfifo_val
= ((inb(sym_ctest5
) & 0x03) << 8) | inb(sym_dfifo
);
601 bytesleft
= (dfifo_val
- (dbc
& 0x3ff)) & 0x3ff;
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
++;
612 outb(sym_ctest3
, 0x04);
614 t
->address
+= t
->count
- dbc
;
617 /* adjust for data that didn't make it to the target */
618 t
->address
-= bytesleft
;
619 t
->count
+= bytesleft
;
621 kprintf(" a=0x%08x, l=0x%08x\n",
622 t
->address
, t
->count
);
624 s
->active
->dataout_phys
= s
->active
->table_phys
+ 8*(t
->count
? n
: n
+1);
625 t
->count
|= s
->op_out
;
627 t
->count
= LE(t
->count
);
628 t
->address
= LE(t
->address
);
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
);
658 /* nothing happened... must be somebody else's problem */
659 release_spinlock(&(s
->hwlock
));
660 return B_UNHANDLED_INTERRUPT
;
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
673 ** 3. If there is nothing else to do, go to "idle" and wait for signal or
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
;
685 out32(sym_dsp
, LE(s
->sram_phys
+ Ent_switch_resel
));
686 //kp("sym: restart @ %08x / reselected\n",Ent_switch_resel);
688 out32(sym_dsp
, LE(s
->sram_phys
+ Ent_switch
));
689 //kp("sym: restart @ %08x / selected\n", Ent_switch);
693 out32(sym_dsa
, LE(s
->startqueue
->priv_phys
+ ADJUST_PRIV_TO_DSA
));
695 s
->startqueue
->status
= status_selecting
;
697 out32(sym_dsp
, LE(s
->sram_phys
+ Ent_start
));
698 //kp("sym: restart @ %08x / started\n", Ent_start);
701 out32(sym_dsp
, LE(s
->sram_phys
+ Ent_idle
));
702 //kp("sym: restart @ %08x / idle\n", Ent_idle);
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
);
724 /* reset the SCSI bus */
725 dprintf("symbios%ld: scsi bus reset\n",s
->num
);
726 outb(sym_scntl1
, sym_scntl1_rst
);
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
747 /* enable all fatal SCSI ints */
748 outb(sym_sien0
, sym_sien0_ma
| sym_sien0_sge
| sym_sien0_udc
| sym_sien0_rst
|
750 outb(sym_sien1
, sym_sien1_sto
| sym_sien1_sbmc
); // XXX
752 /* sel / hth timeouts */
753 outb(sym_stime0
, 0xbb);
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
++) {
778 if(s
->status
== TEST
){
780 return B_ERROR
; //XXX teardown
787 out32(sym_dsp
, LE(s
->sram_phys
+ Ent_idle
));
788 d_printf("symbios%ld: started script\n",s
->num
);
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",
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",
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
;
842 physical_entry pe
[2];
846 targ
= s
->targ
+ ccb
->cam_ch
.cam_target_id
;
848 if(targ
->flags
& tf_ignore
){
849 ccbh
->cam_status
= CAM_SEL_TIMEOUT
;
853 if(ccb
->cam_ch
.cam_flags
& CAM_CDB_POINTER
) {
854 cdb
= ccb
->cam_cdb_io
.cam_cdb_ptr
;
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);
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);
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]);*/
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
){
898 command
[0] = 0x03; /* request_sense */
899 command
[1] = ccb
->cam_ch
.cam_target_lun
<< 5;
902 command
[4] = ccb
->cam_sense_len
;
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
;
912 ccb
->cam_ch
.cam_status
|= CAM_AUTOSNS_VALID
;
916 ccbh
->cam_status
= CAM_REQ_CMP
;
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
);
929 ccbh
->cam_status
= CAM_SEL_TIMEOUT
;
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
);
943 ** sim_path_inquiry returns info on the target/lun.
945 static long sim_path_inquiry(Symbios
*s
, CCB_HEADER
*ccbh
)
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
;
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
);
983 ** scsi_sim_action performes the scsi i/o command embedded in the
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
){
993 return sim_execute_scsi_io(s
,ccbh
);
995 return sim_path_inquiry(s
,ccbh
);
996 case XPT_EXTENDED_PATH_INQ
:
997 return sim_extended_path_inquiry(s
, ccbh
);
999 ccbh
->cam_status
= CAM_REQ_INVALID
;
1004 static void reloc_script(Symbios
*s
)
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);
1022 outb(sym_dien
, sym_dien_sir
);
1029 outb(sym_dmode
, /*( sym_dmode_diom | sym_dmode_siom, 0 )*/ 0); /* FIXME: ??? */
1032 static uint32
sym_readclock(Symbios
*s
)
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
++){
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 :) */
1049 outb(sym_stime1
, 11); /* delay of 128ms */
1050 while (!(inb(sym_sist1
) & sym_sist1_gen
)) snooze(250);
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 */
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
)
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
;
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
;
1088 sprintf(name
,"sym%d:sram",num
);
1089 if(flags
& symf_sram
){
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){
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
);
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
){
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
);
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
);
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);
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 */
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 */
1198 s
->sclk
= sym_readclock(s
);
1199 dprintf("symbios%ld: clock is %ldKHz\n",s
->num
,s
->sclk
);
1203 outb(sym_stest3
, 0x80); /* leave TolerANT on */
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 */
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*/
1225 /* 160 MHz - divide by 4, 8 */
1231 s
->maxoffset
= (flags
& symf_short
) ? 8 : 15 ;
1235 /* calculate values for 160MHz clock */
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);
1246 /* calculate values for 80MHz clock */
1248 s
->syncinfo
[s
->syncsize
].sxfer
= i
<< 5;
1250 s
->syncinfo
[s
->syncsize
].scntl3
= s
->scntl3
| 0x90; /* /2, Ultra */
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);
1261 /* calculate values for 40MHz clock */
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);
1270 for(i
=0;i
<s
->syncsize
;i
++){
1271 dprintf("symbios%ld: syncinfo[%d] = { %02x, %02x, %d ns, %d ns }\n",
1273 s
->syncinfo
[i
].sxfer
, s
->syncinfo
[i
].scntl3
,
1274 s
->syncinfo
[i
].period_ns
, s
->syncinfo
[i
].period
);
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
;
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
){
1303 s
->op_in
= OP_WDATA_IN
;
1304 s
->op_out
= OP_WDATA_OUT
;
1307 s
->op_in
= OP_NDATA_IN
;
1308 s
->op_out
= OP_NDATA_OUT
;
1322 ** Multiple Card Cruft
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...
1351 sim_install_symbios(void)
1353 int i
, j
, iobase
, irq
;
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");*/
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");
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
);
1393 d_printf("symbios%d: cannot allocate cardinfo\n",cardcount
);
1404 static status_t
std_ops(int32 op
, ...)
1409 set_dprintf_enabled(true);
1411 if (get_module(pci_name
, (module_info
**) &pci
) != B_OK
)
1414 if (get_module(cam_name
, (module_info
**) &cam
) != B_OK
) {
1415 put_module(pci_name
);
1419 if(sim_install_symbios()){
1423 put_module(pci_name
);
1424 put_module(cam_name
);
1427 case B_MODULE_UNINIT
:
1428 put_module(pci_name
);
1429 put_module(cam_name
);
1438 sim_module_info sim_symbios_module
= {
1439 { "busses/scsi/53c8xx/v1", 0, &std_ops
}
1443 module_info
*modules
[] =
1445 (module_info
*) &sim_symbios_module
,