📄 aha152x.c
字号:
/*
Test, if port_base is valid.
*/
static int aha152x_porttest(int port_base)
{
int i;
if(check_region(port_base, TEST-SCSISEQ))
return 0;
SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
for(i=0; i<16; i++)
SETPORT( STACK, i );
SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
for(i=0; i<16 && GETPORT(STACK)==i; i++)
;
return(i==16);
}
int aha152x_detect(int hostno)
{
int i, j, ok;
aha152x_config conf;
struct sigaction sa;
int interrupt_level;
#if defined(DEBUG_RACE)
enter_driver("detect");
#endif
printk("aha152x: Probing: ");
if(setup_called)
{
printk("processing commandline: ");
if(setup_called!=4)
{
printk("\naha152x: %s\n", setup_str );
printk("aha152x: usage: aha152x=<PORTBASE>,<IRQ>,<SCSI ID>,<RECONNECT>\n");
panic("aha152x panics in line %d", __LINE__);
}
port_base = setup_portbase;
interrupt_level = setup_irq;
this_host = setup_scsiid;
can_disconnect = setup_reconnect;
for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
;
if(i==PORT_COUNT)
{
printk("unknown portbase 0x%03x\n", port_base);
panic("aha152x panics in line %d", __LINE__);
}
if(!aha152x_porttest(port_base))
{
printk("portbase 0x%03x fails probe\n", port_base);
panic("aha152x panics in line %d", __LINE__);
}
i=0;
while(ints[i] && (interrupt_level!=ints[i]))
i++;
if(!ints[i])
{
printk("illegal IRQ %d\n", interrupt_level);
panic("aha152x panics in line %d", __LINE__);
}
if( (this_host < 0) || (this_host > 7) )
{
printk("illegal SCSI ID %d\n", this_host);
panic("aha152x panics in line %d", __LINE__);
}
if( (can_disconnect < 0) || (can_disconnect > 1) )
{
printk("reconnect %d should be 0 or 1\n", can_disconnect);
panic("aha152x panics in line %d", __LINE__);
}
printk("ok, ");
}
else
{
#if !defined(SKIP_BIOSTEST)
printk("BIOS test: ");
ok=0;
for( i=0; i < ADDRESS_COUNT && !ok; i++)
for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
(void *) signatures[j].signature,
(int) signatures[j].sig_length);
if(!ok)
{
#if defined(DEBUG_RACE)
leave_driver("(1) detect");
#endif
printk("failed\n");
return 0;
}
printk("ok, ");
#endif /* !SKIP_BIOSTEST */
#if !defined(PORTBASE)
printk("porttest: ");
for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++)
;
if(i==PORT_COUNT)
{
printk("failed\n");
#if defined(DEBUG_RACE)
leave_driver("(2) detect");
#endif
return 0;
}
else
port_base=ports[i];
printk("ok, ");
#else
port_base=PORTBASE;
#endif /* !PORTBASE */
#if defined(AUTOCONF)
conf.cf_port = (GETPORT(PORTA)<<8) + GETPORT(PORTB);
interrupt_level = ints[conf.cf_irq];
this_host = conf.cf_id;
can_disconnect = conf.cf_tardisc;
printk("auto configuration: ok, ");
#endif /* AUTOCONF */
#if defined(IRQ)
interrupt_level = IRQ;
#endif
#if defined(SCSI_ID)
this_host = SCSI_ID;
#endif
#if defined(RECONNECT)
can_disconnect=RECONNECT;
#endif
}
printk("detection complete\n");
sa.sa_handler = aha152x_intr;
sa.sa_flags = SA_INTERRUPT;
sa.sa_mask = 0;
sa.sa_restorer = NULL;
ok = irqaction( interrupt_level, &sa);
if(ok<0)
{
if(ok == -EINVAL)
{
printk("aha152x: bad IRQ %d.\n", interrupt_level);
printk(" Contact author.\n");
}
else
if( ok == -EBUSY)
printk( "aha152x: IRQ %d already in use. Configure another.\n",
interrupt_level);
else
{
printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
interrupt_level);
printk(" Contact author.\n");
}
panic("aha152x: driver needs an IRQ.\n");
}
SETPORT( SCSIID, this_host << 4 );
scsi_hosts[hostno].this_id=this_host;
if(can_disconnect)
scsi_hosts[hostno].can_queue=AHA152X_MAXQUEUE;
/* RESET OUT */
SETBITS(SCSISEQ, SCSIRSTO );
do_pause(5);
CLRBITS(SCSISEQ, SCSIRSTO );
do_pause(10);
aha152x_reset(NULL);
printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=enabled\n",
port_base, interrupt_level, this_host, can_disconnect ? "enabled" : "disabled" );
snarf_region(port_base, TEST-SCSISEQ); /* Register */
/* not expecting any interrupts */
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
#if defined(DEBUG_RACE)
leave_driver("(3) detect");
#endif
SETBITS( DMACNTRL0, INTEN);
return 1;
}
/*
* return the name of the thing
*/
const char *aha152x_info(void)
{
#if defined(DEBUG_RACE)
enter_driver("info");
leave_driver("info");
#else
#if defined(DEBUG_INFO)
printk("\naha152x: info()\n");
#endif
#endif
return(aha152x_id);
}
/*
* Queue a command and setup interrupts for a free bus.
*/
int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
#if defined(DEBUG_RACE)
enter_driver("queue");
#else
#if defined(DEBUG_QUEUE)
printk("aha152x: queue(), ");
#endif
#endif
#if defined(DEBUG_QUEUE)
printk( "SCpnt (target = %d lun = %d cmnd = 0x%02x pieces = %d size = %u), ",
SCpnt->target,
SCpnt->lun,
*(unsigned char *)SCpnt->cmnd,
SCpnt->use_sg,
SCpnt->request_bufflen );
disp_ports();
#endif
SCpnt->scsi_done = done;
/* setup scratch area
SCp.ptr : buffer pointer
SCp.this_residual : buffer length
SCp.buffer : next buffer
SCp.buffers_residual : left buffers in list
SCp.phase : current state of the command */
SCpnt->SCp.phase = not_issued;
if (SCpnt->use_sg)
{
SCpnt->SCp.buffer = (struct scatterlist *)SCpnt->request_buffer;
SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
}
else
{
SCpnt->SCp.ptr = (char *)SCpnt->request_buffer;
SCpnt->SCp.this_residual = SCpnt->request_bufflen;
SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
}
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0;
SCpnt->SCp.have_data_in = 0;
SCpnt->SCp.sent_command = 0;
/* Turn led on, when this is the first command. */
cli();
commands++;
if(commands==1)
SETPORT( PORTA, 1 );
#if defined(DEBUG_QUEUES)
printk("i+ (%d), ", commands );
#endif
append_SC( &issue_SC, SCpnt);
/* Enable bus free interrupt, when we aren't currently on the bus */
if(!current_SC)
{
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
}
sti();
return 0;
}
/*
* We only support command in interrupt-driven fashion
*/
int aha152x_command( Scsi_Cmnd *SCpnt )
{
printk( "aha152x: interrupt driven driver; use aha152x_queue()\n" );
return -1;
}
/*
* Abort a queued command
* (commands that are on the bus can't be aborted easily)
*/
int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
{
Scsi_Cmnd *ptr, *prev;
cli();
#if defined(DEBUG_ABORT)
printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned long) SCpnt );
#endif
show_queues();
/* look for command in issue queue */
for( ptr=issue_SC, prev=NULL;
ptr && ptr!=SCpnt;
prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
;
if(ptr)
{
/* dequeue */
if(prev)
prev->host_scribble = ptr->host_scribble;
else
issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
sti();
ptr->host_scribble = NULL;
ptr->result = (code ? code : DID_ABORT ) << 16;
ptr->done(ptr);
return 0;
}
/* Fail abortion, if we're on the bus */
if (current_SC)
{
sti();
return -1;
}
/* look for command in disconnected queue */
for( ptr=disconnected_SC, prev=NULL;
ptr && ptr!=SCpnt;
prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
;
if(ptr && TESTLO(SSTAT1, BUSFREE) )
printk("bus busy but no current command, ");
if(ptr && TESTHI(SSTAT1, BUSFREE) )
{
/* dequeue */
if(prev)
prev->host_scribble = ptr->host_scribble;
else
issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
/* set command current and initiate selection,
let the interrupt routine take care of the abortion */
current_SC = ptr;
ptr->SCp.phase = in_selection|aborted;
SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
/* 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 );
SETBITS( DMACNTRL0, INTEN );
abort_result=0;
sti();
/* sleep until the abortion is complete */
sleep_on( &abortion_complete );
return abort_result;
}
else
printk("aha152x: bus busy but no current command\n");
/* command wasn't found */
sti();
return 0;
}
/*
* Restore default values to the AIC-6260 registers and reset the fifos
*/
static void aha152x_reset_ports(void)
{
/* disable interrupts */
SETPORT(DMACNTRL0, RSTFIFO);
SETPORT(SCSISEQ, 0);
SETPORT(SXFRCTL1, 0);
SETPORT( SCSISIG, 0);
SETPORT(SCSIRATE, 0);
/* clear all interrupt conditions */
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
SETPORT(SSTAT4, SYNCERR|FWERR|FRERR);
SETPORT(DMACNTRL0, 0);
SETPORT(DMACNTRL1, 0);
SETPORT(BRSTCNTRL, 0xf1);
/* clear SCSI fifo and transfer count */
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
SETPORT(SXFRCTL0, CH1);
/* enable interrupts */
SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
}
/*
* Reset registers, reset a hanging bus and
* kill active and disconnected commands
*/
int aha152x_reset(Scsi_Cmnd * __unused)
{
Scsi_Cmnd *ptr;
aha152x_reset_ports();
/* Reset, if bus hangs */
if( TESTLO( SSTAT1, BUSFREE ) )
{
CLRBITS( DMACNTRL0, INTEN );
#if defined( DEBUG_RESET )
printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
#endif
show_queues();
if(current_SC)
{
current_SC->host_scribble = NULL;
current_SC->result = DID_RESET << 16;
current_SC->done(current_SC);
current_SC=NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -