📄 fdomain.c
字号:
if (data_count == 1) {
*current_SC->SCp.ptr++ = inb( Read_FIFO_port );
--current_SC->SCp.this_residual;
} else {
data_count >>= 1; /* Number of words */
insw( Read_FIFO_port, current_SC->SCp.ptr, data_count );
current_SC->SCp.ptr += 2 * data_count;
current_SC->SCp.this_residual -= 2 * data_count;
}
}
if (!current_SC->SCp.this_residual
&& current_SC->SCp.buffers_residual) {
--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 (done) {
#if EVERY_ACCESS
printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
#endif
#if ERRORS_ONLY
if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
unsigned char key;
unsigned char code;
unsigned char qualifier;
key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
& 0x0f;
code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
qualifier = (unsigned char)(*((char *)current_SC->request_buffer
+ 13));
if (!(key == UNIT_ATTENTION && (code == 0x29 || !code))
&& !(key == NOT_READY
&& code == 0x04
&& (!qualifier || qualifier == 0x02 || qualifier == 0x01))
&& !(key == ILLEGAL_REQUEST && (code == 0x25
|| code == 0x24
|| !code)))
printk( "Future Domain: REQUEST SENSE "
"Key = %x, Code = %x, Qualifier = %x\n",
key, code, qualifier );
}
}
#endif
#if EVERY_ACCESS
printk( "BEFORE MY_DONE. . ." );
#endif
my_done( (current_SC->SCp.Status & 0xff)
| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
#if EVERY_ACCESS
printk( "RETURNING.\n" );
#endif
} else {
if (current_SC->SCp.phase & disconnect) {
outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port );
outb( 0x00, SCSI_Cntl_port );
} else {
outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
}
}
#if DEBUG_RACE
in_interrupt_flag = 0;
#endif
return;
}
int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
if (in_command) {
panic( "Future Domain: fdomain_16x0_queue() NOT REENTRANT!\n" );
}
#if EVERY_ACCESS
printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
SCpnt->target,
*(unsigned char *)SCpnt->cmnd,
SCpnt->use_sg,
SCpnt->request_bufflen );
#endif
fdomain_make_bus_idle();
current_SC = SCpnt; /* Save this for the done function */
current_SC->scsi_done = done;
/* Initialize static data */
if (current_SC->use_sg) {
current_SC->SCp.buffer =
(struct scatterlist *)current_SC->request_buffer;
current_SC->SCp.ptr = current_SC->SCp.buffer->address;
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
} else {
current_SC->SCp.ptr = (char *)current_SC->request_buffer;
current_SC->SCp.this_residual = current_SC->request_bufflen;
current_SC->SCp.buffer = NULL;
current_SC->SCp.buffers_residual = 0;
}
current_SC->SCp.Status = 0;
current_SC->SCp.Message = 0;
current_SC->SCp.have_data_in = 0;
current_SC->SCp.sent_command = 0;
current_SC->SCp.phase = in_arbitration;
/* Start arbitration */
outb( 0x00, Interrupt_Cntl_port );
outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */
++in_command;
outb( 0x20, Interrupt_Cntl_port );
outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
return 0;
}
/* The following code, which simulates the old-style command function, was
taken from Tommy Thorn's aha1542.c file. This code is Copyright (C)
1992 Tommy Thorn. */
static volatile int internal_done_flag = 0;
static volatile int internal_done_errcode = 0;
static void internal_done( Scsi_Cmnd *SCpnt )
{
internal_done_errcode = SCpnt->result;
++internal_done_flag;
}
int fdomain_16x0_command( Scsi_Cmnd *SCpnt )
{
fdomain_16x0_queue( SCpnt, internal_done );
while (!internal_done_flag)
;
internal_done_flag = 0;
return internal_done_errcode;
}
/* End of code derived from Tommy Thorn's work. */
void print_info( Scsi_Cmnd *SCpnt )
{
unsigned int imr;
unsigned int irr;
unsigned int isr;
print_banner();
switch (SCpnt->SCp.phase) {
case in_arbitration: printk( "arbitration " ); break;
case in_selection: printk( "selection " ); break;
case in_other: printk( "other " ); break;
default: printk( "unknown " ); break;
}
printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
SCpnt->SCp.phase,
SCpnt->target,
*(unsigned char *)SCpnt->cmnd,
SCpnt->use_sg,
SCpnt->request_bufflen );
printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
SCpnt->SCp.sent_command,
SCpnt->SCp.have_data_in,
SCpnt->timeout );
#if DEBUG_RACE
printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
#endif
imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
outb( 0x0a, 0xa0 );
irr = inb( 0xa0 ) << 8;
outb( 0x0a, 0x20 );
irr += inb( 0x20 );
outb( 0x0b, 0xa0 );
isr = inb( 0xa0 ) << 8;
outb( 0x0b, 0x20 );
isr += inb( 0x20 );
/* Print out interesting information */
printk( "IMR = 0x%04x", imr );
if (imr & (1 << interrupt_level))
printk( " (masked)" );
printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port ) );
printk( "TMC Status = 0x%02x", inb( TMC_Status_port ) );
if (inb( TMC_Status_port & 1))
printk( " (interrupt)" );
printk( "\n" );
printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) );
if (inb( Interrupt_Status_port ) & 0x08)
printk( " (enabled)" );
printk( "\n" );
if (chip == tmc18c50) {
printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status ) );
printk( "Int. Condition = 0x%02x\n",
inb( port_base + Interrupt_Cond ) );
}
printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) );
if (chip == tmc18c50)
printk( "Configuration 2 = 0x%02x\n",
inb( port_base + Configuration2 ) );
}
int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
{
#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
printk( "Future Domain: Abort " );
#endif
cli();
if (!in_command) {
#if EVERY_ACCESS || ERRORS_ONLY
printk( " (not in command)\n" );
#endif
sti();
return 0;
} else {
#if EVERY_ACCESS || ERRORS_ONLY
printk( " code = %d\n", code );
#endif
}
#if DEBUG_ABORT
print_info( SCpnt );
#endif
fdomain_make_bus_idle();
current_SC->SCp.phase |= aborted;
current_SC->result = code ? code : DID_ABORT;
sti();
/* Aborts are not done well. . . */
my_done( code << 16 );
return 0;
}
int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
{
#if DEBUG_RESET
static int called_once = 0;
#endif
#if ERRORS_ONLY
printk( "Future Domain: SCSI Bus Reset\n" );
#endif
#if DEBUG_RESET
if (called_once) print_info( current_SC );
called_once = 1;
#endif
outb( 1, SCSI_Cntl_port );
do_pause( 2 );
outb( 0, SCSI_Cntl_port );
do_pause( 115 );
outb( 0, SCSI_Mode_Cntl_port );
outb( PARITY_MASK, TMC_Cntl_port );
/* Unless this is the very first call (i.e., SCPnt == NULL), everything
is probably hosed at this point. We will, however, try to keep
things going by informing the high-level code that we need help. */
if (SCpnt)
SCpnt->flags |= NEEDS_JUMPSTART;
return 0;
}
int fdomain_16x0_biosparam( int size, int dev, int *info_array )
{
int drive;
struct drive_info {
unsigned short cylinders;
unsigned char heads;
unsigned char sectors;
} *i;
/* NOTES:
The RAM area starts at 0x1f00 from the bios_base address.
For BIOS Version 2.0:
The drive parameter table seems to start at 0x1f30.
The first byte's purpose is not known.
Next is the cylinder, head, and sector information.
The last 4 bytes appear to be the drive's size in sectors.
The other bytes in the drive parameter table are unknown.
If anyone figures them out, please send me mail, and I will
update these notes.
Tape drives do not get placed in this table.
There is another table at 0x1fea:
If the byte is 0x01, then the SCSI ID is not in use.
If the byte is 0x18 or 0x48, then the SCSI ID is in use,
although tapes don't seem to be in this table. I haven't
seen any other numbers (in a limited sample).
0x1f2d is a drive count (i.e., not including tapes)
The table at 0x1fcc are I/O ports addresses for the various
operations. I calculate these by hand in this driver code.
For BIOS Version 3.2:
The drive parameter table starts at 0x1f70. Each entry is
0x0a bytes long. Heads are one less than we need to report.
*/
drive = MINOR(dev) / 16;
if (bios_major == 2) {
i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
info_array[0] = i->heads;
info_array[1] = i->sectors;
info_array[2] = i->cylinders;
} else if (bios_major == 3) { /* Appears to be the same for 3.0 and 3.2 */
i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
info_array[0] = i->heads + 1;
info_array[1] = i->sectors;
info_array[2] = i->cylinders;
} else {
/* How the data is stored in the RAM area is very BIOS-dependent.
Therefore, assume a version 3 layout, and check for validity. */
i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
info_array[0] = i->heads + 1;
info_array[1] = i->sectors;
info_array[2] = i->cylinders;
if (!info_array[0]
|| !info_array[1]
|| !info_array[2]
|| info_array[2] > 1024 /* DOS uses only 10 bits.
Should this be changed
to support larger drives?
I.e., will the controller
"do the right thing"?
*/
) {
info_array[0]
= info_array[1]
= info_array[2]
= 0;
}
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -