📄 aha152x.c
字号:
while(disconnected_SC)
{
ptr = disconnected_SC;
disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
ptr->host_scribble = NULL;
ptr->result = DID_RESET << 16;
ptr->done(ptr);
}
/* RESET OUT */
SETPORT(SCSISEQ, SCSIRSTO);
do_pause(5);
SETPORT(SCSISEQ, 0);
do_pause(10);
SETPORT(SIMODE0, 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
SETPORT( DMACNTRL0, INTEN );
}
return 0;
}
/*
* Return the "logical geometry"
*/
int aha152x_biosparam( int size, int dev, int *info_array )
{
#if defined(DEBUG_RACE)
enter_driver("biosparam");
#else
#if defined(DEBUG_BIOSPARAM)
printk("\naha152x: biosparam(), ");
#endif
#endif
#if defined(DEBUG_BIOSPARAM)
printk("dev=%x, size=%d, ", dev, size);
#endif
/* I took this from other SCSI drivers, since it provides
the correct data for my devices. */
info_array[0]=64;
info_array[1]=32;
info_array[2]=size>>11;
#if defined(DEBUG_BIOSPARAM)
printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
info_array[0], info_array[1], info_array[2]);
printk("WARNING: check, if the bios geometry is correct.\n");
#endif
#if defined(DEBUG_RACE)
leave_driver("biosparam");
#endif
return 0;
}
/*
* Internal done function
*/
void aha152x_done( int error )
{
Scsi_Cmnd *done_SC;
#if defined(DEBUG_DONE)
printk("\naha152x: done(), ");
disp_ports();
#endif
if (current_SC)
{
#if defined(DEBUG_DONE)
printk("done(%x), ", error);
#endif
cli();
done_SC = current_SC;
current_SC = NULL;
/* turn led off, when no commands are in the driver */
commands--;
if(!commands)
SETPORT( PORTA, 0 ); /* turn led off */
#if defined(DEBUG_QUEUES)
printk("ok (%d), ", commands);
#endif
sti();
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
#if defined(DEBUG_PHASES)
printk("BUS FREE loop, ");
#endif
while( TESTLO( SSTAT1, BUSFREE ) )
;
#if defined(DEBUG_PHASES)
printk("BUS FREE\n");
#endif
done_SC->result = error;
if(done_SC->scsi_done)
{
#if defined(DEBUG_DONE)
printk("calling scsi_done, ");
#endif
done_SC->scsi_done( done_SC );
#if defined(DEBUG_DONE)
printk("done returned, ");
#endif
}
else
panic( "aha152x: current_SC->scsi_done() == NULL" );
}
else
aha152x_panic( "done() called outside of command" );
}
/*
* Interrupts handler (main routine of the driver)
*/
void aha152x_intr( int irqno )
{
int done=0, phase;
#if defined(DEBUG_RACE)
enter_driver("intr");
#else
#if defined(DEBUG_INTR)
printk("\naha152x: intr(), ");
#endif
#endif
/* no more interrupts from the controller, while we busy.
INTEN has to be restored, when we're ready to leave
intr(). To avoid race conditions we have to return
immediately afterwards. */
CLRBITS( DMACNTRL0, INTEN);
sti();
/* disconnected target is trying to reconnect.
Only possible, if we have disconnected nexuses and
nothing is occuping the bus.
*/
if( TESTHI( SSTAT0, SELDI ) &&
disconnected_SC &&
( !current_SC || ( current_SC->SCp.phase & in_selection ) )
)
{
int identify_msg, target, i;
/* Avoid conflicts when a target reconnects
while we are trying to connect to another. */
if(current_SC)
{
#if defined(DEBUG_QUEUES)
printk("i+, ");
#endif
cli();
append_SC( &issue_SC, current_SC);
current_SC=NULL;
sti();
}
/* disable sequences */
SETPORT( SCSISEQ, 0 );
SETPORT( SSTAT0, CLRSELDI );
SETPORT( SSTAT1, CLRBUSFREE );
#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
printk("reselected, ");
#endif
i = GETPORT(SELID) & ~(1 << this_host);
target=0;
if(i)
for( ; (i & 1)==0; target++, i>>=1)
;
else
aha152x_panic("reconnecting target unknown");
#if defined(DEBUG_QUEUES)
printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
#endif
SETPORT( SCSIID, (this_host << OID_) | target );
SETPORT( SCSISEQ, ENRESELI );
if(TESTLO( SSTAT0, SELDI ))
aha152x_panic("RESELI failed");
SETPORT( SCSISIG, P_MSGI );
/* Get identify message */
if((i=getphase())!=P_MSGI)
{
printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
aha152x_panic("unknown lun");
}
SETPORT( SCSISEQ, 0 );
SETPORT( SXFRCTL0, CH1);
identify_msg = GETPORT(SCSIBUS);
if(!(identify_msg & IDENTIFY_BASE))
{
printk("target=%d, inbound message (%02x) != IDENTIFY\n",
target, identify_msg);
aha152x_panic("unknown lun");
}
make_acklow();
getphase();
#if defined(DEBUG_QUEUES)
printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
#endif
cli();
#if defined(DEBUG_QUEUES)
printk("d-, ");
#endif
current_SC = remove_SC( &disconnected_SC,
target,
identify_msg & 0x3f );
if(!current_SC)
{
printk("lun=%d, ", identify_msg & 0x3f );
aha152x_panic("no disconnected command for that lun");
}
current_SC->SCp.phase &= ~disconnected;
sti();
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS );
#if defined(DEBUG_RACE)
leave_driver("(reselected) intr");
#endif
SETBITS( DMACNTRL0, INTEN);
return;
}
/* Check, if we aren't busy with a command */
if(!current_SC)
{
/* bus is free to issue a queued command */
if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
{
cli();
#if defined(DEBUG_QUEUES)
printk("i-, ");
#endif
current_SC = remove_first_SC( &issue_SC );
sti();
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
printk("issueing command, ");
#endif
current_SC->SCp.phase = in_selection;
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
printk("selecting %d, ", current_SC->target);
#endif
SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
/* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
SETPORT( SXFRCTL1, ENSPCHK|ENSTIMER);
/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
SETPORT( SIMODE1, ENSELTIMO );
/* Enable SELECTION OUT sequence */
SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
#if defined(DEBUG_RACE)
leave_driver("(selecting) intr");
#endif
SETBITS( DMACNTRL0, INTEN );
return;
}
/* No command we are busy with and no new to issue */
printk("aha152x: ignoring spurious interrupt, nothing to do\n");
return;
}
/* the bus is busy with something */
#if defined(DEBUG_INTR)
disp_ports();
#endif
/* we are waiting for the result of a selection attempt */
if(current_SC->SCp.phase & in_selection)
{
if( TESTLO( SSTAT1, SELTO ) )
/* no timeout */
if( TESTHI( SSTAT0, SELDO ) )
{
/* clear BUS FREE interrupt */
SETPORT( SSTAT1, CLRBUSFREE);
/* Disable SELECTION OUT sequence */
CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
/* Disable SELECTION OUT DONE interrupt */
CLRBITS(SIMODE0, ENSELDO);
CLRBITS(SIMODE1, ENSELTIMO);
if( TESTLO(SSTAT0, SELDO) )
{
printk("aha152x: passing bus free condition\n");
#if defined(DEBUG_RACE)
leave_driver("(passing bus free) intr");
#endif
SETBITS( DMACNTRL0, INTEN);
if(current_SC->SCp.phase & aborted)
{
abort_result=1;
wake_up( &abortion_complete );
}
aha152x_done( DID_NO_CONNECT << 16 );
return;
}
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
printk("SELDO (SELID=%x), ", GETPORT(SELID));
#endif
/* selection was done */
SETPORT( SSTAT0, CLRSELDO );
#if defined(DEBUG_ABORT)
if(current_SC->SCp.phase & aborted)
printk("(ABORT) target selected, ");
#endif
current_SC->SCp.phase &= ~in_selection;
current_SC->SCp.phase |= in_other;
#if defined(DEBUG_RACE)
leave_driver("(SELDO) intr");
#endif
SETPORT( SCSISIG, P_MSGO );
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENREQINIT );
SETBITS( DMACNTRL0, INTEN);
return;
}
else
aha152x_panic("neither timeout nor selection\007");
else
{
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
printk("SELTO, ");
#endif
/* end selection attempt */
CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
/* timeout */
SETPORT( SSTAT1, CLRSELTIMO );
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
leave_driver("(SELTO) intr");
#endif
if(current_SC->SCp.phase & aborted)
{
#if defined(DEBUG_ABORT)
printk("(ABORT) selection timeout, ");
#endif
abort_result=1;
wake_up( &abortion_complete );
}
if( TESTLO( SSTAT0, SELINGO ) )
/* ARBITRATION not won */
aha152x_done( DID_BUS_BUSY << 16 );
else
/* ARBITRATION won, but SELECTION failed */
aha152x_done( DID_NO_CONNECT << 16 );
return;
}
}
/* enable interrupt, when target leaves current phase */
phase = getphase();
if(!(phase & ~P_MASK)) /* "real" phase */
SETPORT(SCSISIG, phase);
SETPORT(SSTAT1, CLRPHASECHG);
current_SC->SCp.phase =
(current_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16 );
/* information transfer phase */
switch( phase )
{
case P_MSGO: /* MESSAGE OUT */
{
unsigned char message;
#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
printk("MESSAGE OUT, ");
#endif
if( current_SC->SCp.phase & aborted )
{
#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
printk("ABORT, ");
#endif
message=ABORT;
}
else
/* If we didn't identify yet, do it. Otherwise there's nothing to do,
but reject (probably we got an message before, that we have to
reject (SDTR, WDTR, etc.) */
if( !(current_SC->SCp.phase & sent_ident))
{
message=IDENTIFY(can_disconnect,current_SC->lun);
#if defined(DEBUG_MSGO)
printk("IDENTIFY (reconnect=%s;lun=%d), ",
can_disconnect ? "enabled" : "disabled", current_SC->lun);
#endif
}
else
{
message=MESSAGE_REJECT;
#if defined(DEBUG_MSGO)
printk("REJECT, ");
#endif
}
CLRBITS( SXFRCTL0, ENDMA);
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT );
/* wait for data latch to become ready or a phase change */
while( TESTLO( DMASTAT, INTSTAT ) )
;
if( TESTHI( SSTAT1, PHASEMIS ) )
aha152x_panic("unable to send message");
/* Leave MESSAGE OUT after transfer */
SETPORT( SSTAT1, CLRATNO);
SETPORT( SCSIDAT, message );
make_acklow();
getphase();
if(message==IDENTIFY(can_disconnect,current_SC->lun))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -