📄 fd_mcs.c
字号:
Read_FIFO_port = port + Read_FIFO; Read_SCSI_Data_port = port + Read_SCSI_Data; SCSI_Cntl_port = port + SCSI_Cntl; SCSI_Data_NoACK_port = port + SCSI_Data_NoACK; SCSI_Status_port = port + SCSI_Status; TMC_Cntl_port = port + TMC_Cntl; TMC_Status_port = port + TMC_Status; Write_FIFO_port = port + Write_FIFO; Write_SCSI_Data_port = port + Write_SCSI_Data; Bytes_Read = 0; Bytes_Written = 0; INTR_Processed = 0; /* say something */ print_banner( shpnt ); /* reset */ 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 ); /* done reset */#if DO_DETECT /* scan devices attached */ { const int buflen = 255; int i, j, retcode; Scsi_Cmnd SCinit; unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 }; unsigned char do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 }; unsigned char do_read_capacity[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char buf[buflen]; SCinit.request_buffer = SCinit.buffer = buf; SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; SCinit.use_sg = 0; SCinit.lun = 0; SCinit.host = shpnt; printk( "fd_mcs: detection routine scanning for devices:\n" ); for (i = 0; i < 8; i++) { if (i == shpnt->this_id) /* Skip host adapter */ continue; SCinit.target = i; memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); retcode = fd_mcs_command(&SCinit); if (!retcode) { memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); retcode = fd_mcs_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 = fd_mcs_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)\n", ((capacity + 5L) / 10L), size ); } } } } }#endif } } if (found == FD_MAX_HOSTS) { printk( "fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS); break; } } return found;}const char *fd_mcs_info(struct Scsi_Host *shpnt){ return adapter_name;}static int TOTAL_INTR = 0;/* * inout : decides on the direction of the dataflow and the meaning of the * variables * buffer: If inout==FALSE data is being written to it else read from it * *start: If inout==FALSE start of the valid data in the buffer * offset: If inout==FALSE offset from the beginning of the imaginary file * from which we start writing into the buffer * length: If inout==FALSE max number of bytes to be written into the buffer * else number of bytes in the buffer */int fd_mcs_proc_info( char *buffer, char **start, off_t offset, int length, int hostno, int inout ){ struct Scsi_Host *shpnt; int len = 0; int i; if (inout) return(-ENOSYS); *start = buffer + offset; for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); shpnt = hosts[i]; if (!shpnt) { return(-ENOENT); } else { len += sprintf(buffer+len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION); len += sprintf(buffer+len, "HOST #%d: %s\n", hostno, adapter_name); len += sprintf(buffer+len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT); len += sprintf(buffer+len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written); } if ((len -= offset) <= 0) return 0; if (len > length) len = length; return len;} static int fd_mcs_select(struct Scsi_Host *shpnt, int target ){ int status; unsigned long timeout; outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port ); /* Stop arbitration and enable parity */ outb( PARITY_MASK, TMC_Cntl_port ); timeout = 350; /* 350mS -- because of timeouts (was 250mS) */ do { 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; } udelay(1000); /* wait one msec */ } while (--timeout); /* Make bus idle */ fd_mcs_make_bus_idle(shpnt);#if EVERY_ACCESS if (!target) printk( "Selection failed\n" );#endif#if ERRORS_ONLY if (!target) { static int flag = 0; if (!flag) /* Skip first failure for all chips. */ ++flag; else printk( "fd_mcs: Selection failed\n" ); }#endif return 1;}static void my_done( struct Scsi_Host *shpnt, int error ){ if (in_command) { in_command = 0; outb( 0x00, Interrupt_Cntl_port ); fd_mcs_make_bus_idle(shpnt); current_SC->result = error; current_SC->scsi_done( current_SC ); } else { panic( "fd_mcs: my_done() called outside of command\n" ); }#if DEBUG_RACE in_interrupt_flag = 0;#endif}/* only my_done needs to be protected */static void fd_mcs_intr( int irq, void *dev_id, struct pt_regs * regs ){ unsigned long flags; int status; int done = 0; unsigned data_count, tmp_count; int i = 0; struct Scsi_Host *shpnt; TOTAL_INTR++; /* search for one adapter-response on shared interrupt */ while ((shpnt = hosts[i++])) { if ((inb(TMC_Status_port)) & 1) break; } /* return if some other device on this IRQ caused the interrupt */ if (!shpnt) { return; } INTR_Processed++; outb( 0x00, Interrupt_Cntl_port ); /* Abort calls my_done, so we do nothing here. */ if (current_SC->SCp.phase & aborted) {#if DEBUG_ABORT printk( "Interrupt after abort, ignoring\n" );#endif /* return; */ }#if DEBUG_RACE ++in_interrupt_flag;#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 spin_lock_irqsave(&io_request_lock, flags); my_done( shpnt, DID_BUS_BUSY << 16 ); spin_unlock_irqrestore(&io_request_lock, flags); return; } current_SC->SCp.phase = in_selection; outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port ); outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port ); /* Stop arbitration and enable parity */ outb( 0x10 | PARITY_MASK, TMC_Cntl_port );#if DEBUG_RACE in_interrupt_flag = 0;#endif return; } else if (current_SC->SCp.phase & in_selection) { status = inb( SCSI_Status_port ); if (!(status & 0x01)) { /* Try again, for slow devices */ if (fd_mcs_select(shpnt, current_SC->target )) {#if EVERY_ACCESS printk( " SFAIL " );#endif spin_lock_irqsave(&io_request_lock, flags); my_done( shpnt, DID_NO_CONNECT << 16 ); spin_unlock_irqrestore(&io_request_lock, flags); return; } else {#if EVERY_ACCESS printk( " AltSel " );#endif /* Stop arbitration and enable parity */ outb( 0x10 | PARITY_MASK, TMC_Cntl_port ); } } current_SC->SCp.phase = in_other; outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); outb( 0x80, SCSI_Cntl_port );#if DEBUG_RACE in_interrupt_flag = 0;#endif return; } /* current_SC->SCp.phase == in_other: this is the body of the routine */ status = inb( SCSI_Status_port ); if (status & 0x10) { /* REQ */ switch (status & 0x0e) { case 0x08: /* COMMAND OUT */ 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 break; case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ if (chip != tmc1800 && !current_SC->SCp.have_data_in) { current_SC->SCp.have_data_in = -1; outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); } break; case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ if (chip != tmc1800 && !current_SC->SCp.have_data_in) { current_SC->SCp.have_data_in = 1; outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); } 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 && current_SC->SCp.Status != 8) { printk( "ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->target, current_SC->cmnd[0], current_SC->SCp.Status ); }#endif break; case 0x0a: /* MESSAGE OUT */ outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */ 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 DEBUG_MESSAGES || EVERY_ACCESS if (current_SC->SCp.Message) { printk( "fd_mcs: message = %x\n", current_SC->SCp.Message ); }#endif break; } } if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) { /* We have to get the FIFO direction correct, so I've made a table based on the SCSI Standard of which commands appear to require a DATA OUT phase. */ /* p. 94: Command for all device types CHANGE DEFINITION 40 DATA OUT COMPARE 39 DATA OUT COPY 18 DATA OUT COPY AND VERIFY 3a DATA OUT INQUIRY 12 LOG SELECT 4c DATA OUT LOG SENSE 4d MODE SELECT (6) 15 DATA OUT MODE SELECT (10) 55 DATA OUT MODE SENSE (6) 1a MODE SENSE (10) 5a READ BUFFER 3c RECEIVE DIAGNOSTIC RESULTS 1c REQUEST SENSE 03 SEND DIAGNOSTIC 1d DATA OUT TEST UNIT READY 00 WRITE BUFFER 3b DATA OUT p.178: Commands for direct-access devices (not listed on p. 94) FORMAT UNIT 04 DATA OUT LOCK-UNLOCK CACHE 36 PRE-FETCH 34 PREVENT-ALLOW MEDIUM REMOVAL 1e READ (6)/RECEIVE 08 READ (10) 3c READ CAPACITY 25 READ DEFECT DATA (10) 37 READ LONG 3e REASSIGN BLOCKS 07 DATA OUT RELEASE 17 RESERVE 16 DATA OUT REZERO UNIT/REWIND 01 SEARCH DATA EQUAL (10) 31 DATA OUT SEARCH DATA HIGH (10) 30 DATA OUT SEARCH DATA LOW (10) 32 DATA OUT SEEK (6) 0b SEEK (10) 2b SET LIMITS (10) 33 START STOP UNIT 1b SYNCHRONIZE CACHE 35 VERIFY (10) 2f WRITE (6)/PRINT/SEND 0a DATA OUT WRITE (10)/SEND 2a DATA OUT WRITE AND VERIFY (10) 2e DATA OUT WRITE LONG 3f DATA OUT WRITE SAME 41 DATA OUT ? p. 261: Commands for sequential-access devices (not previously listed) ERASE 19 LOAD UNLOAD 1b LOCATE 2b READ BLOCK LIMITS 05 READ POSITION 34 READ REVERSE 0f RECOVER BUFFERED DATA 14 SPACE 11 WRITE FILEMARKS 10 ? p. 298: Commands for printer devices (not previously listed) ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) ***** SLEW AND PRINT 0b DATA OUT -- same as seek STOP PRINT 1b SYNCHRONIZE BUFFER 10 p. 315: Commands for processor devices (not previously listed) p. 321: Commands for write-once devices (not previously listed) MEDIUM SCAN 38 READ (12) a8 SEARCH DATA EQUAL (12) b1 DATA OUT SEARCH DATA HIGH (12) b0 DATA OUT SEARCH DATA LOW (12) b2 DATA OUT SET LIMITS (12) b3 VERIFY (12) af WRITE (12) aa DATA OUT WRITE AND VERIFY (12) ae DATA OUT p. 332: Commands for CD-ROM devices (not previously listed) PAUSE/RESUME 4b PLAY AUDIO (10) 45 PLAY AUDIO (12) a5 PLAY AUDIO MSF 47 PLAY TRACK RELATIVE (10) 49 PLAY TRACK RELATIVE (12) a9 READ HEADER 44 READ SUB-CHANNEL 42 READ TOC 43 p. 370: Commands for scanner devices (not previously listed) GET DATA BUFFER STATUS 34 GET WINDOW 25 OBJECT POSITION 31 SCAN 1b SET WINDOW 24 DATA OUT p. 391: Commands for optical memory devices (not listed) ERASE (10) 2c ERASE (12) ac MEDIUM SCAN 38 DATA OUT READ DEFECT DATA (12) b7 READ GENERATION 29 READ UPDATED BLOCK 2d UPDATE BLOCK 3d DATA OUT p. 419: Commands for medium changer devices (not listed) EXCHANGE MEDIUM 46 INITIALIZE ELEMENT STATUS 07 MOVE MEDIUM a5 POSITION TO ELEMENT 2b READ ELEMENT STATUS b8 REQUEST VOL. ELEMENT ADDRESS b5 SEND VOLUME TAG b6 DATA OUT p. 454: Commands for communications devices (not listed previously) GET MESSAGE (6) 08 GET MESSAGE (10) 28 GET MESSAGE (12) a8 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -