extractedLnx/linux/drivers/scsi/aha152x.c_aha152x_intr.c
void aha152x_intr( int irqno, struct pt_regs * regs )
{
unsigned int flags;
int done=0, phase;
#if defined(DEBUG_RACE)
enter_driver("intr");
#else
#if defined(DEBUG_INTR)
if(aha152x_debug & 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(); /* Yes, sti() really needs to be here */
/* disconnected target is trying to reconnect.
Only possible, if we have disconnected nexuses and
nothing is occupying 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)
if(aha152x_debug & debug_queues)
printk("i+, ");
#endif
save_flags(flags);
cli();
append_SC( &issue_SC, current_SC);
current_SC=NULL;
restore_flags(flags);
}
/* disable sequences */
SETPORT( SCSISEQ, 0 );
SETPORT( SSTAT0, CLRSELDI );
SETPORT( SSTAT1, CLRBUSFREE );
#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_queues|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)
if(aha152x_debug & 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)
if(aha152x_debug & debug_queues)
printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
#endif
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
if(aha152x_debug & 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;
restore_flags(flags);
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#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)
{
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
printk("i-, ");
#endif
current_SC = remove_first_SC( &issue_SC );
restore_flags(flags);
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
printk("issuing command, ");
#endif
current_SC->SCp.phase = in_selection;
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_selection|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, can_doparity ? (ENSPCHK|ENSTIMER) : 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)
if(aha152x_debug & 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=SCSI_ABORT_ERROR;
abortion_complete++;
}
aha152x_done( DID_NO_CONNECT << 16 );
return;
}
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_selection|debug_phases))
printk("SELDO (SELID=%x), ", GETPORT(SELID));
#endif
/* selection was done */
SETPORT( SSTAT0, CLRSELDO );
#if defined(DEBUG_ABORT)
if((aha152x_debug & debug_abort) && (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|ENBUSFREE );
SETBITS( DMACNTRL0, INTEN);
return;
}
else
aha152x_panic("neither timeout nor selection\007");
else
{
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_selection|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)
if(aha152x_debug & debug_abort)
printk("(ABORT) selection timeout, ");
#endif
abort_result=SCSI_ABORT_ERROR;
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)
if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
printk("MESSAGE OUT, ");
#endif
if( current_SC->SCp.phase & aborted )
{
#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
if(aha152x_debug & (debug_msgo|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)
if(aha152x_debug & debug_msgo)
printk("IDENTIFY (reconnect=%s;lun=%d), ",
can_disconnect ? "enabled" : "disabled", current_SC->lun);
#endif
}
else
{
message=MESSAGE_REJECT;
#if defined(DEBUG_MSGO)
if(aha152x_debug & debug_msgo)
printk("REJECT, ");
#endif
}
CLRBITS( SXFRCTL0, ENDMA);
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
/* 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))
current_SC->SCp.phase |= sent_ident;
if(message==ABORT)
{
/* revive abort(); abort() enables interrupts */
abort_result=SCSI_ABORT_SUCCESS;
abortion_complete++;
current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
/* exit */
SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
leave_driver("(ABORT) intr");
#endif
aha152x_done(DID_ABORT<<16);
return;
}
}
break;
case P_CMD: /* COMMAND phase */
#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
printk("COMMAND, ");
#endif
if( !(current_SC->SCp.sent_command) )
{
if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
/* reset fifo and enable writes */
SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
/* clear transfer count and scsi fifo */
SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
/* missing phase raises INTSTAT */
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
printk("waiting, ");
#endif
/* wait for FIFO to get empty */
while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
;
if( TESTHI( SSTAT1, PHASEMIS ) )
aha152x_panic("target left COMMAND phase");
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
{
printk("DFIFOEMP, outsw (%d bytes, %d words), ",
current_SC->cmd_len, current_SC->cmd_len >> 1 );
disp_ports();
}
#endif
outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 );
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
{
printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
disp_ports();
}
#endif
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
printk("waiting for SEMPTY, ");
#endif
/* wait for SCSI FIFO to get empty.
very important to send complete commands. */
while( TESTLO ( SSTAT2, SEMPTY ) )
;
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
printk("SEMPTY, ");
#endif
CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
/* transfer can be considered ended, when SCSIEN reads back zero */
while( TESTHI( SXFRCTL0, SCSIEN ) )
;
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
printk("!SEMPTY, ");
#endif
CLRBITS(DMACNTRL0, ENDMA);
#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
if(debug_cmd & debug_intr)
printk("sent %d/%d command bytes, ", GETSTCNT(),
current_SC->cmd_len);
#endif
}
else
aha152x_panic("Nothing to sent while in COMMAND OUT");
break;
case P_MSGI: /* MESSAGE IN phase */
#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
printk("MESSAGE IN, ");
#endif
SETPORT( SXFRCTL0, CH1);
SETPORT( SIMODE0, 0);
SETPORT( SIMODE1, ENBUSFREE);
while( phase == P_MSGI )
{
current_SC->SCp.Message = GETPORT( SCSIBUS );
switch(current_SC->SCp.Message)
{
case DISCONNECT:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_msgi|debug_phases))
printk("target disconnected, ");
#endif
current_SC->SCp.Message = 0;
current_SC->SCp.phase |= disconnected;
if(!can_disconnect)
aha152x_panic("target was not allowed to disconnect");
break;
case COMMAND_COMPLETE:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_msgi|debug_phases))
printk("inbound message ( COMMAND COMPLETE ), ");
#endif
done++;
break;
case MESSAGE_REJECT:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("inbound message ( MESSAGE REJECT ), ");
#endif
break;
case SAVE_POINTERS:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("inbound message ( SAVE DATA POINTERS ), ");
#endif
break;
case EXTENDED_MESSAGE:
{
int i, code;
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("inbound message ( EXTENDED MESSAGE ), ");
#endif
make_acklow();
if(getphase()!=P_MSGI)
break;
i=GETPORT(SCSIBUS);
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("length (%d), code ( ", i);
#endif
make_acklow();
if(getphase()!=P_MSGI)
break;
code = GETPORT(SCSIBUS);
switch( code )
{
case 0x00:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("MODIFY DATA POINTER ");
#endif
SETPORT(SCSISIG, P_MSGI|ATNO);
break;
case 0x01:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
#endif
SETPORT(SCSISIG, P_MSGI|ATNO);
break;
case 0x02:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("EXTENDED IDENTIFY ");
#endif
break;
case 0x03:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("WIDE DATA TRANSFER REQUEST ");
#endif
SETPORT(SCSISIG, P_MSGI|ATNO);
break;
default:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
if( code & 0x80 )
printk("reserved (%d) ", code );
else
printk("vendor specific (%d) ", code);
#endif
SETPORT(SCSISIG, P_MSGI|ATNO);
break;
}
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk(" ), data ( ");
#endif
while( --i && (make_acklow(), getphase()==P_MSGI))
{
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk("%x ", GETPORT(SCSIBUS) );
#else
GETPORT(SCSIBUS);
#endif
}
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
printk(" ), ");
#endif
/* We reject all extended messages. To do this
we just enter MSGO by asserting ATN. Since
we have already identified a REJECT message
will be sent. */
SETPORT(SCSISIG, P_MSGI|ATNO);
}
break;
default:
printk("unsupported inbound message %x, ", current_SC->SCp.Message);
break;
}
make_acklow();
phase=getphase();
}
/* clear SCSI fifo on BUSFREE */
if(phase==P_BUSFREE)
SETPORT(SXFRCTL0, CH1|CLRCH1);
if(current_SC->SCp.phase & disconnected)
{
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
printk("d+, ");
#endif
append_SC( &disconnected_SC, current_SC);
current_SC = NULL;
restore_flags(flags);
SETBITS( SCSISEQ, ENRESELI );
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
SETBITS( DMACNTRL0, INTEN );
return;
}
break;
case P_STATUS: /* STATUS IN phase */
#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_status|debug_intr|debug_phases))
printk("STATUS, ");
#endif
SETPORT( SXFRCTL0, CH1);
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
if( TESTHI( SSTAT1, PHASEMIS ) )
printk("aha152x: passing STATUS phase");
current_SC->SCp.Status = GETPORT( SCSIBUS );
make_acklow();
getphase();
#if defined(DEBUG_STATUS)
if(aha152x_debug & debug_status)
{
printk("inbound status ");
print_status( current_SC->SCp.Status );
printk(", ");
}
#endif
break;
case P_DATAI: /* DATA IN phase */
{
int fifodata, data_count, done;
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
printk("DATA IN, ");
#endif
if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
/* reset host fifo */
SETPORT(DMACNTRL0, RSTFIFO);
SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
/* done is set when the FIFO is empty after the target left DATA IN */
done=0;
/* while the target stays in DATA to transfer data */
while ( !done )
{
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
printk("expecting data, ");
#endif
/* wait for PHASEMIS or full FIFO */
while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
;
if( TESTHI( DMASTAT, DFIFOFULL ) )
fifodata=GETPORT(FIFOSTAT);
else
{
/* wait for SCSI fifo to get empty */
while( TESTLO( SSTAT2, SEMPTY ) )
;
/* rest of data in FIFO */
fifodata=GETPORT(FIFOSTAT);
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
printk("last transfer, ");
#endif
done=1;
}
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
printk("fifodata=%d, ", fifodata);
#endif
while( fifodata && current_SC->SCp.this_residual )
{
data_count=fifodata;
/* limit data transfer to size of first sg buffer */
if (data_count > current_SC->SCp.this_residual)
data_count = current_SC->SCp.this_residual;
fifodata -= data_count;
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
printk("data_count=%d, ", data_count);
#endif
if(data_count&1)
{
/* get a single byte in byte mode */
SETBITS(DMACNTRL0, _8BIT );
*current_SC->SCp.ptr++ = GETPORT( DATAPORT );
current_SC->SCp.this_residual--;
}
if(data_count>1)
{
CLRBITS(DMACNTRL0, _8BIT );
data_count >>= 1; /* Number of words */
insw( DATAPORT, current_SC->SCp.ptr, data_count );
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
/* show what comes with the last transfer */
if(done)
{
int i;
unsigned char *data;
printk("data on last transfer (%d bytes: ",
2*data_count);
data = (unsigned char *) current_SC->SCp.ptr;
for( i=0; i<2*data_count; i++)
printk("%2x ", *data++);
printk("), ");
}
#endif
current_SC->SCp.ptr += 2 * data_count;
current_SC->SCp.this_residual -= 2 * data_count;
}
/* if this buffer is full and there are more buffers left */
if (!current_SC->SCp.this_residual &&
current_SC->SCp.buffers_residual)
{
/* advance to next buffer */
current_SC->SCp.buffers_residual--;
current_SC->SCp.buffer++;
current_SC->SCp.ptr =
current_SC->SCp.buffer->address;
current_SC->SCp.this_residual =
current_SC->SCp.buffer->length;
}
}
/*
* Fifo should be empty
*/
if(fifodata>0)
{
printk("aha152x: more data than expected (%d bytes)\n",
GETPORT(FIFOSTAT));
SETBITS(DMACNTRL0, _8BIT );
printk("aha152x: data ( ");
while(fifodata--)
printk("%2x ", GETPORT( DATAPORT ));
printk(")\n");
}
#if defined(DEBUG_DATAI)
if(aha152x_debug & debug_datai)
if(!fifodata)
printk("fifo empty, ");
else
printk("something left in fifo, ");
#endif
}
#if defined(DEBUG_DATAI)
if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
printk("left buffers (buffers=%d, bytes=%d), ",
current_SC->SCp.buffers_residual,
current_SC->SCp.this_residual);
#endif
/* transfer can be considered ended, when SCSIEN reads back zero */
CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
while( TESTHI( SXFRCTL0, SCSIEN ) )
;
CLRBITS(DMACNTRL0, ENDMA );
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
if(aha152x_debug & (debug_datai|debug_intr))
printk("got %d bytes, ", GETSTCNT());
#endif
current_SC->SCp.have_data_in++;
}
break;
case P_DATAO: /* DATA OUT phase */
{
int data_count;
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
printk("DATA OUT, ");
#endif
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("got data to send (bytes=%d, buffers=%d), ",
current_SC->SCp.this_residual,
current_SC->SCp.buffers_residual );
#endif
if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
{
printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
aha152x_panic("FIFO should be empty");
}
SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
/* while current buffer is not empty or
there are more buffers to transfer */
while( TESTLO( SSTAT1, PHASEMIS ) &&
(current_SC->SCp.this_residual ||
current_SC->SCp.buffers_residual) )
{
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
current_SC->SCp.this_residual,
current_SC->SCp.buffers_residual);
#endif
/* transfer rest of buffer, but max. 128 byte */
data_count = current_SC->SCp.this_residual > 128 ?
128 : current_SC->SCp.this_residual ;
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("data_count=%d, ", data_count);
#endif
if(data_count&1)
{
/* put a single byte in byte mode */
SETBITS(DMACNTRL0, _8BIT );
SETPORT(DATAPORT, *current_SC->SCp.ptr++);
current_SC->SCp.this_residual--;
}
if(data_count>1)
{
CLRBITS(DMACNTRL0, _8BIT );
data_count >>= 1; /* Number of words */
outsw( DATAPORT, current_SC->SCp.ptr, data_count );
current_SC->SCp.ptr += 2 * data_count;
current_SC->SCp.this_residual -= 2 * data_count;
}
/* wait for FIFO to get empty */
while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
;
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("fifo (%d bytes), transfered (%d bytes), ",
GETPORT(FIFOSTAT), GETSTCNT() );
#endif
/* if this buffer is empty and there are more buffers left */
if ( TESTLO( SSTAT1, PHASEMIS ) &&
!current_SC->SCp.this_residual &&
current_SC->SCp.buffers_residual)
{
/* advance to next buffer */
current_SC->SCp.buffers_residual--;
current_SC->SCp.buffer++;
current_SC->SCp.ptr =
current_SC->SCp.buffer->address;
current_SC->SCp.this_residual =
current_SC->SCp.buffer->length;
}
}
if ( current_SC->SCp.this_residual ||
current_SC->SCp.buffers_residual )
{
/* target leaves DATA OUT for an other phase
(perhaps disconnect) */
/* data in fifos has to be resend */
data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
data_count += GETPORT(FIFOSTAT) ;
current_SC->SCp.ptr -= data_count;
current_SC->SCp.this_residual += data_count;
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
current_SC->SCp.this_residual,
current_SC->SCp.buffers_residual,
data_count );
#endif
SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
CLRBITS(DMACNTRL0, ENDMA);
}
else
{
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("waiting for SCSI fifo to get empty, ");
#endif
/* wait for SCSI fifo to get empty */
while( TESTLO( SSTAT2, SEMPTY ) )
;
#if defined(DEBUG_DATAO)
if(aha152x_debug & debug_datao)
printk("ok, left data (bytes=%d, buffers=%d) ",
current_SC->SCp.this_residual,
current_SC->SCp.buffers_residual);
#endif
CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
/* transfer can be considered ended, when SCSIEN reads back zero */
while( TESTHI( SXFRCTL0, SCSIEN ) )
;
CLRBITS(DMACNTRL0, ENDMA);
}
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
if(aha152x_debug & (debug_datao|debug_intr))
printk("sent %d data bytes, ", GETSTCNT() );
#endif
}
break;
case P_BUSFREE: /* BUSFREE */
#if defined(DEBUG_RACE)
leave_driver("(BUSFREE) intr");
#endif
#if defined(DEBUG_PHASES)
if(aha152x_debug & debug_phases)
printk("unexpected BUS FREE, ");
#endif
current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
aha152x_done( DID_ERROR << 16 ); /* Don't know any better */
return;
break;
case P_PARITY: /* parity error in DATA phase */
#if defined(DEBUG_RACE)
leave_driver("(DID_PARITY) intr");
#endif
printk("PARITY error in DATA phase, ");
current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
SETBITS( DMACNTRL0, INTEN );
aha152x_done( DID_PARITY << 16 );
return;
break;
default:
printk("aha152x: unexpected phase\n");
break;
}
if(done)
{
#if defined(DEBUG_INTR)
if(aha152x_debug & debug_intr)
printk("command done.\n");
#endif
#if defined(DEBUG_RACE)
leave_driver("(done) intr");
#endif
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
SETPORT(SCSISEQ, disconnected_SC ? ENRESELI : 0 );
SETBITS( DMACNTRL0, INTEN );
aha152x_done( (current_SC->SCp.Status & 0xff)
| ( (current_SC->SCp.Message & 0xff) << 8)
| ( DID_OK << 16) );
#if defined(DEBUG_RACE)
printk("done returned (DID_OK: Status=%x; Message=%x).\n",
current_SC->SCp.Status, current_SC->SCp.Message);
#endif
return;
}
if(current_SC)
current_SC->SCp.phase |= 1<<16 ;
SETPORT( SIMODE0, 0 );
SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#if defined(DEBUG_INTR)
if(aha152x_debug & debug_intr)
disp_enintr();
#endif
#if defined(DEBUG_RACE)
leave_driver("(PHASEEND) intr");
#endif
SETBITS( DMACNTRL0, INTEN);
return;
}
Generated by GNU enscript 1.6.4.