fd_mcs.c

来自「linux 内核源代码」· C语言 代码 · 共 1,367 行 · 第 1/3 页

C
1,367
字号
					FIFO_Size = 0x800;	/* 2k FIFO */					printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);				}				/* *************************************************** */#endif				/* IBM/ANSI scsi scan ordering */				/* Stick this back in when the scsi.c changes are there */				shpnt->reverse_ordering = 1;				/* saving info */				hosts[found++] = shpnt;				shpnt->this_id = id;				shpnt->irq = irq;				shpnt->io_port = port;				shpnt->n_io_port = 0x10;				/* save */				bios_base = bios;				adapter_mask = (1 << id);				/* save more */				SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;				FIFO_Data_Count_port = port + FIFO_Data_Count;				Interrupt_Cntl_port = port + Interrupt_Cntl;				Interrupt_Status_port = port + Interrupt_Status;				Interrupt_Cond_port = port + Interrupt_Cond;				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 (found == FD_MAX_HOSTS) {			printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);			break;		}	}	return found;}static 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 */static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout){	int len = 0;	if (inout)		return (-ENOSYS);	*start = buffer + offset;	len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);	len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, 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 irqreturn_t fd_mcs_intr(int irq, void *dev_id){	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 IRQ_NONE;	}	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 IRQ_HANDLED; */	}#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(shpnt->host_lock, flags);			my_done(shpnt, DID_BUS_BUSY << 16);			spin_unlock_irqrestore(shpnt->host_lock, flags);			return IRQ_HANDLED;		}		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 << scmd_id(current_SC)), 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 IRQ_HANDLED;	} 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, scmd_id(current_SC))) {#if EVERY_ACCESS				printk(" SFAIL ");#endif				spin_lock_irqsave(shpnt->host_lock, flags);				my_done(shpnt, DID_NO_CONNECT << 16);				spin_unlock_irqrestore(shpnt->host_lock, flags);				return IRQ_HANDLED;			} 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 IRQ_HANDLED;	}	/* 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->device->id, 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		 */		switch (current_SC->cmnd[0]) {		case CHANGE_DEFINITION:		case COMPARE:		case COPY:		case COPY_VERIFY:		case LOG_SELECT:		case MODE_SELECT:		case MODE_SELECT_10:		case SEND_DIAGNOSTIC:		case WRITE_BUFFER:		case FORMAT_UNIT:		case REASSIGN_BLOCKS:		case RESERVE:		case SEARCH_EQUAL:		case SEARCH_HIGH:		case SEARCH_LOW:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?