📄 fdomain.c
字号:
printk( "Future Domain detection routine scanning for devices:\n" ); for (i = 0; i < 8; i++) { SCinit.target = i; if (i == 6) continue; /* The host adapter is at SCSI ID 6 */ memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); retcode = fdomain_16x0_command(&SCinit); if (!retcode) { memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); retcode = fdomain_16x0_command(&SCinit); if (!retcode) { printk( " SCSI ID %d: ", i ); for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity)); retcode = fdomain_16x0_command(&SCinit); if (!retcode) { unsigned long blocks, size, capacity; blocks = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; printk( "%lu MB (%lu byte blocks)", ((capacity + 5L) / 10L), size ); } else { memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); retcode = fdomain_16x0_command(&SCinit); } printk ("\n" ); } else { memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); retcode = fdomain_16x0_command(&SCinit); } } }#endif this_host = hostnum; if (!QUEUE || !interrupt_level) { printk( "Future Domain: *NO* interrupt level selected!\n" ); printk( " COMMAND QUEUEING DISABLED!\n" ); can_queue = scsi_hosts[this_host].can_queue = 0; scsi_hosts[this_host].sg_tablesize = SG_NONE; } else { /* Register the IRQ with the kernel */ sa.sa_handler = fdomain_16x0_intr; sa.sa_flags = SA_INTERRUPT; sa.sa_mask = 0; sa.sa_restorer = NULL; retcode = irqaction( interrupt_level, &sa ); if (retcode < 0) { if (retcode == -EINVAL) { printk( "Future Domain: IRQ %d is bad!\n", interrupt_level ); printk( " This shouldn't happen: REPORT TO RIK!\n" ); } else if (retcode == -EBUSY) { printk( "Future Domain: IRQ %d is already in use!\n", interrupt_level ); printk( " Please use another IRQ for the FD card!\n" ); } else { printk( "Future Domain: Error getting IRQ %d\n", interrupt_level ); printk( " This shouldn't happen: REPORT TO RIK!\n" ); } printk( " COMMAND QUEUEING DISABLED!\n" ); can_queue = scsi_hosts[this_host].can_queue = 0; scsi_hosts[this_host].sg_tablesize = SG_NONE; } else { printk( "Future Domain: IRQ %d requested from kernel\n", interrupt_level ); } } return 1;}const char *fdomain_16x0_info(void){ static char buffer[] = "Future Domain TMC-1660/TMC-1680 SCSI driver version " VERSION "\n"; return buffer;}static int fdomain_arbitrate( void ){ int status = 0; unsigned long timeout;#if EVERY_ACCESS printk( "SCSI: fdomain_arbitrate()\n" );#endif outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */ outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */ timeout = jiffies + 50; /* 500 mS */ while (jiffies < timeout) { status = inb( TMC_Status_port ); /* Read adapter status */ if (status & 0x02) return 0; /* Arbitration complete */ } /* Make bus idle */ fdomain_make_bus_idle();#if EVERY_ACCESS printk( "Arbitration failed, status = %x\n", status );#endif#if ERRORS_ONLY printk( "SCSI (Future Domain): Arbitration failed, status = %x", status );#endif return 1;}static int fdomain_select( int target ){ int status; unsigned long timeout; /* Send our address OR'd with target address */ outb( 0x40 | (1 << target), SCSI_Data_NoACK_port ); if (RESELECTION && can_queue) outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */ else outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ /* Stop arbitration (also set FIFO for output and enable parity) */ outb( 0xc0 | PARITY_MASK, TMC_Cntl_port ); timeout = jiffies + 25; /* 250mS */ while (jiffies < timeout) { status = inb( SCSI_Status_port ); /* Read adapter status */ if (status & 1) { /* Busy asserted */ /* Enable SCSI Bus (on error, should make bus idle with 0) */ outb( 0x80, SCSI_Cntl_port ); return 0; } } /* Make bus idle */ fdomain_make_bus_idle();#if EVERY_ACCESS if (!target) printk( "Selection failed\n" );#endif#if ERRORS_ONLY if (!target) printk( "SCSI (Future Domain): Selection failed" );#endif return 1;}void my_done( int error ){ if (in_command) { in_command = 0; in_interrupt_code = 0; outb( 0x00, Interrupt_Cntl_port ); fdomain_make_bus_idle(); current_SC->result = error; if (current_SC->scsi_done) current_SC->scsi_done( current_SC ); else panic( "SCSI (Future Domain): current_SC->scsi_done() == NULL" ); } else { panic( "SCSI (Future Domain): my_done() called outside of command\n" ); }}void fdomain_16x0_intr( int unused ){ int status; int done = 0; unsigned data_count; sti(); if (in_interrupt_code) panic( "SCSI (Future Domain): fdomain_16x0_intr() NOT REENTRANT!\n" ); else ++in_interrupt_code; outb( 0x00, Interrupt_Cntl_port ); if (current_SC->SCp.phase & aborted) {#if EVERY_ACCESS if (current_SC->SCp.phase & (in_other || disconnect)) printk( "aborted (%s) = %d, ", current_SC->SCp.phase & in_other ? "in_other" : "disconnect", current_SC->result ); else printk( "aborted = %d, ", current_SC->result );#endif /* Force retry for timeouts after selection complete */ if (current_SC->SCp.phase & (in_other || disconnect)) { fdomain_16x0_reset(); my_done( DID_RESET << 16 ); } else { my_done( current_SC->result << 16 ); } return; } /* We usually have one spurious interrupt after each command. Ignore it. */ if (!in_command) { /* Spurious interrupt */ in_interrupt_code = 0; return; }#if RESELECTION if (current_SC->SCp.phase & disconnect) { printk( " RECON %x ", inb( SCSI_Data_NoACK_port ) ); current_SC->SCp.phase = in_other; outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); outb( 0x84, SCSI_Cntl_port ); while ( (status = inb( SCSI_Status_port )) & 0x20 ) { printk( "s = %x, ", status ); } outb( 0x80, SCSI_Cntl_port ); } else#endif if (current_SC->SCp.phase & in_arbitration) { status = inb( TMC_Status_port ); /* Read adapter status */ if (!(status & 0x02)) {#if EVERY_ACCESS printk( " AFAIL " );#endif my_done( DID_BUS_BUSY << 16 ); return; } current_SC->SCp.phase = in_selection; outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port ); outb( 0x40 | (1 << current_SC->target), SCSI_Data_NoACK_port );#if RESELECTION outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */#else outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */#endif /* Stop arbitration (also set FIFO for output and enable parity) */ outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); in_interrupt_code = 0; return; } else if (current_SC->SCp.phase & in_selection) { status = inb( SCSI_Status_port ); if (!(status & 0x01)) { /* Try again, for slow devices */ if (fdomain_select( current_SC->target )) {#if EVERY_ACCESS printk( " SFAIL " );#endif my_done( DID_NO_CONNECT << 16 ); return; } else {#if EVERY_ACCESS printk( " AltSel " );#endif /* Stop arbitration (also set FIFO for output and enable parity) */ outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); } } current_SC->SCp.phase = in_other; in_interrupt_code = 0; outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );#if RESELECTION outb( 0x88, SCSI_Cntl_port );#else outb( 0x80, SCSI_Cntl_port );#endif return; } /* current_SC->SCp.phase == in_other: this is the body of the routine */ switch (current_SC->cmnd[0]) { case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a: case 0x2e: case 0x3b: case 0xea: case 0x3f: while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) {#if EVERY_ACCESS printk( "DC=%d, ", data_count );#endif if (data_count > current_SC->SCp.this_residual) data_count = current_SC->SCp.this_residual; if (data_count > 0) {#if EVERY_ACCESS printk( "%d OUT, ", data_count );#endif if (data_count == 1) { outb( *current_SC->SCp.ptr++, Write_FIFO_port ); --current_SC->SCp.this_residual; } else { data_count >>= 1; outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port ); current_SC->SCp.ptr += 2 * data_count; current_SC->SCp.this_residual -= 2 * data_count; } } if (!current_SC->SCp.this_residual) { if (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; } else break; } } break; default: if (!current_SC->SCp.have_data_in) { outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); ++current_SC->SCp.have_data_in; } else { while ((data_count = inw( FIFO_Data_Count_port )) != 0) {#if EVERY_ACCESS printk( "DC=%d, ", data_count );#endif if (data_count > current_SC->SCp.this_residual) data_count = current_SC->SCp.this_residual; if (data_count) {#if EVERY_ACCESS printk( "%d IN, ", data_count );#endif 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( current_SC->SCp.ptr, data_count, Read_FIFO_port ); 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; } } } break; } status = inb( SCSI_Status_port ); if (status & 0x10) { /* REQ */ switch (status & 0x0e) { case 0x08: /* COMMAND OUT */#if 0 if (!current_SC->SCp.sent_command) { int i; ++current_SC->SCp.sent_command; for (i = 0; i < COMMAND_SIZE( current_SC->cmnd[0] ); i++) { outb( current_SC->cmnd[i], Write_SCSI_Data_port );#if EVERY_ACCESS printk( "CMD = %x,", current_SC->cmnd[i] );#endif } }#else outb( current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port );#if EVERY_ACCESS printk( "CMD = %x,", current_SC->cmnd[ current_SC->SCp.sent_command - 1] );#endif #endif break; case 0x0c: /* STATUS IN */ current_SC->SCp.Status = inb( Read_SCSI_Data_port );#if EVERY_ACCESS printk( "Status = %x, ", current_SC->SCp.Status );#endif#if ERRORS_ONLY if (current_SC->SCp.Status && current_SC->SCp.Status != 2) { printk( "SCSI (Future Domain): target = %d, command = %x, Status = %x\n", current_SC->target, current_SC->cmnd[0], current_SC->SCp.Status ); }#endif break; case 0x0a: /* MESSAGE OUT */#if RESELECTION if (!(current_SC->SCp.phase & sent_ident)) {#if EVERY_ACCESS printk( " IDENT " );#endif outb( 0x80, SCSI_Cntl_port ); outb( IDENTIFY( 1, 0 ), Write_SCSI_Data_port ); current_SC->SCp.phase |= sent_ident; } else#else outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */#endif break; case 0x0e: /* MESSAGE IN */ current_SC->SCp.Message = inb( Read_SCSI_Data_port );#if EVERY_ACCESS printk( "Message = %x, ", current_SC->SCp.Message );#endif if (!current_SC->SCp.Message) ++done;#if RESELECTION if (current_SC->SCp.Message == DISCONNECT) { printk( " DISCON " ); current_SC->SCp.phase = disconnect; }#endif#if DEBUG_MESSAGES || EVERY_ACCESS if (current_SC->SCp.Message) { printk( "SCSI (Future Domain): Message = %x\n", current_SC->SCp.Message ); }#endif break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -