⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 seagate.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 3 页
字号:
	return 0;      }int seagate_st0x_command (Scsi_Cmnd * SCpnt) {	return internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd, SCpnt->request_buffer,				 SCpnt->request_bufflen, 				 (int) NO_RECONNECT);}	static int internal_command(unsigned char target, unsigned char lun, const void *cmnd,			 void *buff, int bufflen, int reselect) {	int len = 0;	unsigned char *data = NULL;		struct scatterlist *buffer = NULL;	int nobuffs = 0;	int clock;				int temp;#ifdef SLOW_HANDSHAKE	int borken;	/* Does the current target require Very Slow I/O ? */#endif#if (DEBUG & PHASE_DATAIN) || (DEBUG & PHASE_DATOUT) 	int transfered = 0;#endif#if (((DEBUG & PHASE_ETC) == PHASE_ETC) || (DEBUG & PRINT_COMMAND) || \	(DEBUG & PHASE_EXIT))		int i;#endif#if ((DEBUG & PHASE_ETC) == PHASE_ETC)	int phase=0, newphase;#endif	int done = 0;	unsigned char status = 0;		unsigned char message = 0;	register unsigned char status_read;	unsigned transfersize = 0, underflow = 0;	incommand = 0;	st0x_aborted = 0;#ifdef SLOW_HANDSHAKE	borken = (int) scsi_devices[SCint->index].borken;#endif#if (DEBUG & PRINT_COMMAND)	printk ("scsi%d : target = %d, command = ", hostno, target);	print_command((unsigned char *) cmnd);	printk("\n");#endif#if (DEBUG & PHASE_RESELECT)	switch (reselect) {	case RECONNECT_NOW :		printk("scsi%d : reconnecting\n", hostno);		break;#ifdef LINKED	case LINKED_RIGHT : 		printk("scsi%d : connected, can reconnect\n", hostno);		break;	case LINKED_WRONG :		printk("scsi%d : connected to wrong target, can reconnect\n",			hostno);		break;		#endif	case CAN_RECONNECT :		printk("scsi%d : allowed to reconnect\n", hostno);		break;	default :		printk("scsi%d : not allowed to reconnect\n", hostno);	}#endif		if (target == (controller_type == SEAGATE ? 7 : 6))		return DID_BAD_TARGET;/* *	We work it differently depending on if this is is "the first time," *	or a reconnect.  If this is a reselct phase, then SEL will  *	be asserted, and we must skip selection / arbitration phases. */	switch (reselect) {	case RECONNECT_NOW:#if (DEBUG & PHASE_RESELECT)		printk("scsi%d : phase RESELECT \n", hostno);#endif/* *	At this point, we should find the logical or of our ID and the original *	target's ID on the BUS, with BSY, SEL, and I/O signals asserted. * *	After ARBITRATION phase is completed, only SEL, BSY, and the  *	target ID are asserted.  A valid initator ID is not on the bus *	until IO is asserted, so we must wait for that. */				for (clock = jiffies + 10, temp = 0; (jiffies < clock) &&		     !(STATUS & STAT_IO););				if (jiffies >= clock)			{#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : RESELECT timed out while waiting for IO .\n",				hostno);#endif			return (DID_BAD_INTR << 16);			}/*  * 	After I/O is asserted by the target, we can read our ID and its *	ID off of the BUS. */ 		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40)))			{#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : detected reconnect request to different target.\n" 			       "\tData bus = %d\n", hostno, temp);#endif			return (DID_BAD_INTR << 16);			}		if (!(temp & (1 << current_target)))			{			printk("scsi%d : Unexpected reselect interrupt.  Data bus = %d\n",				hostno, temp);			return (DID_BAD_INTR << 16);			}		buffer=current_buffer;	                cmnd=current_cmnd;      /* WDE add */                data=current_data;      /* WDE add */                len=current_bufflen;    /* WDE add */		nobuffs=current_nobuffs;/* * 	We have determined that we have been selected.  At this point,  *	we must respond to the reselection by asserting BSY ourselves */#if 1		CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);#else		CONTROL = (BASE_CMD | CMD_BSY);#endif/* *	The target will drop SEL, and raise BSY, at which time we must drop *	BSY. */		for (clock = jiffies + 10; (jiffies < clock) &&  (STATUS & STAT_SEL););		if (jiffies >= clock)			{ 			CONTROL = (BASE_CMD | CMD_INTR);#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : RESELECT timed out while waiting for SEL.\n",				hostno);#endif			return (DID_BAD_INTR << 16);				 			}		CONTROL = BASE_CMD;/* *	At this point, we have connected with the target and can get  *	on with our lives. */	 		break;	case CAN_RECONNECT:#ifdef LINKED/* * This is a bletcherous hack, just as bad as the Unix #! interpreter stuff. * If it turns out we are using the wrong I_T_L nexus, the easiest way to deal * with it is to go into our INFORMATION TRANSFER PHASE code, send a ABORT  * message on MESSAGE OUT phase, and then loop back to here. */  connect_loop :#endif#if (DEBUG & PHASE_BUS_FREE)		printk ("scsi%d : phase = BUS FREE \n", hostno);#endif/* *	BUS FREE PHASE * * 	On entry, we make sure that the BUS is in a BUS FREE *	phase, by insuring that both BSY and SEL are low for *	at least one bus settle delay.  Several reads help *	eliminate wire glitch. */		clock = jiffies + ST0X_BUS_FREE_DELAY;	#if !defined (ARBITRATE) 		while (((STATUS |  STATUS | STATUS) & 		         (STAT_BSY | STAT_SEL)) && 			 (!st0x_aborted) && (jiffies < clock));		if (jiffies > clock)			return retcode(DID_BUS_BUSY);		else if (st0x_aborted)			return retcode(st0x_aborted);#endif#if (DEBUG & PHASE_SELECTION)		printk("scsi%d : phase = SELECTION\n", hostno);#endif		clock = jiffies + ST0X_SELECTION_DELAY;/* * Arbitration/selection procedure :  * 1.  Disable drivers * 2.  Write HOST adapter address bit * 3.  Set start arbitration. * 4.  We get either ARBITRATION COMPLETE or SELECT at this *     point. * 5.  OR our ID and targets on bus. * 6.  Enable SCSI drivers and asserted SEL and ATTN */		#if defined(ARBITRATE)		cli();	CONTROL = 0;	DATA = (controller_type == SEAGATE) ? 0x80 : 0x40;	CONTROL = CMD_START_ARB; 	sti();	while (!((status_read = STATUS) & (STAT_ARB_CMPL | STAT_SEL)) &&		(jiffies < clock) && !st0x_aborted);	if (!(status_read & STAT_ARB_CMPL)) {#if (DEBUG & PHASE_SELECTION)		if (status_read & STAT_SEL) 			printk("scsi%d : arbitration lost\n", hostno);		else			printk("scsi%d : arbitration timeout.\n", hostno);#endif		CONTROL = BASE_CMD;		return retcode(DID_NO_CONNECT);	};#if (DEBUG & PHASE_SELECTION)	printk("scsi%d : arbitration complete\n", hostno);#endif#endif/* *	When the SCSI device decides that we're gawking at it, it will  *	respond by asserting BUSY on the bus. * * 	Note : the Seagate ST-01/02 product manual says that we should  * 	twiddle the DATA register before the control register.  However, *	this does not work reliably so we do it the other way arround. * *	Probably could be a problem with arbitration too, we really should *	try this with a SCSI protocol or logic analyzer to see what is  *	going on. */	cli();	DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));	CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | 		(reselect ? CMD_ATTN : 0);	sti();		while (!((status_read = STATUS) & STAT_BSY) && 			(jiffies < clock) && !st0x_aborted)#if 0 && (DEBUG & PHASE_SELECTION)		{		temp = clock - jiffies;		if (!(jiffies % 5))			printk("seagate_st0x_timeout : %d            \r",temp);			}		printk("Done.                                             \n");		printk("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", 			hostno, status_read, temp, st0x_aborted);#else		;#endif			if ((jiffies >= clock)  && !(status_read & STAT_BSY))			{#if (DEBUG & PHASE_SELECTION)			printk ("scsi%d : NO CONNECT with target %d, status = %x \n", 				hostno, target, STATUS);#endif			return retcode(DID_NO_CONNECT);			}/* *	If we have been aborted, and we have a command in progress, IE the  *	target still has BSY asserted, then we will reset the bus, and  * 	notify the midlevel driver to expect sense. */		if (st0x_aborted) {			CONTROL = BASE_CMD;			if (STATUS & STAT_BSY) {				printk("scsi%d : BST asserted after we've been aborted.\n",					hostno);				seagate_st0x_reset(NULL);				return retcode(DID_RESET);			}			return retcode(st0x_aborted);		}	/* Establish current pointers.  Take into account scatter / gather */        if ((nobuffs = SCint->use_sg)) {#if (DEBUG & DEBUG_SG)	{	int i;	printk("scsi%d : scatter gather requested, using %d buffers.\n",		hostno, nobuffs);	for (i = 0; i < nobuffs; ++i)		printk("scsi%d : buffer %d address = %08x length = %d\n",			hostno, i, buffer[i].address, buffer[i].length);	}#endif		                buffer = (struct scatterlist *) SCint->buffer;                len = buffer->length;                data = (unsigned char *) buffer->address;        } else {#if (DEBUG & DEBUG_SG)	printk("scsi%d : scatter gather not requested.\n", hostno);#endif                buffer = NULL;                len = SCint->request_bufflen;                data = (unsigned char *) SCint->request_buffer;        }#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT))	printk("scsi%d : len = %d\n", hostno, len);#endif		break;#ifdef LINKED	case LINKED_RIGHT:	    	break;	case LINKED_WRONG:		break;#endif	}/* * 	There are several conditions under which we wish to send a message :  *	1.  When we are allowing disconnect / reconnect, and need to establish *	    the I_T_L nexus via an IDENTIFY with the DiscPriv bit set. * *	2.  When we are doing linked commands, are have the wrong I_T_L nexus *	    established and want to send an ABORT message. */		CONTROL = BASE_CMD | CMD_DRVR_ENABLE | 		(((reselect == CAN_RECONNECT)#ifdef LINKED 		|| (reselect == LINKED_WRONG)#endif 		)  ? CMD_ATTN : 0) ;	/* * 	INFORMATION TRANSFER PHASE * *	The nasty looking read / write inline assembler loops we use for  *	DATAIN and DATAOUT phases are approximately 4-5 times as fast as  *	the 'C' versions - since we're moving 1024 bytes of data, this *	really adds up. */#if ((DEBUG & PHASE_ETC) == PHASE_ETC)	printk("scsi%d : phase = INFORMATION TRANSFER\n", hostno);#endif  	incommand = 1;	transfersize = SCint->transfersize;	underflow = SCint->underflow;/* * 	Now, we poll the device for status information, *	and handle any requests it makes.  Note that since we are unsure of  *	how much data will be flowing across the system, etc and cannot  *	make reasonable timeouts, that we will instead have the midlevel * 	driver handle any timeouts that occur in this phase. */	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) 		{#ifdef PARITY		if (status_read & STAT_PARITY)			{			printk("scsi%d : got parity error\n", hostno);			st0x_aborted = DID_PARITY;			}	#endif		if (status_read & STAT_REQ)			{#if ((DEBUG & PHASE_ETC) == PHASE_ETC)			if ((newphase = (status_read & REQ_MASK)) != phase)				{				phase = newphase;				switch (phase)				{				case REQ_DATAOUT: 					printk("scsi%d : phase = DATA OUT\n",						hostno); 					break;				case REQ_DATAIN : 					printk("scsi%d : phase = DATA IN\n",						hostno); 					break;				case REQ_CMDOUT : 					printk("scsi%d : phase = COMMAND OUT\n",						hostno); 					break;				case REQ_STATIN :					 printk("scsi%d : phase = STATUS IN\n",						hostno); 					break;				case REQ_MSGOUT :					printk("scsi%d : phase = MESSAGE OUT\n",						hostno); 					break;				case REQ_MSGIN :					printk("scsi%d : phase = MESSAGE IN\n",						hostno);					break;				default : 					printk("scsi%d : phase = UNKNOWN\n",						hostno); 					st0x_aborted = DID_ERROR; 				}					}#endif		switch (status_read & REQ_MASK)		{					case REQ_DATAOUT : /* * If we are in fast mode, then we simply splat the data out * in word-sized chunks as fast as we can. */#ifdef FAST if (!len) {#if 0         printk("scsi%d: underflow to target %d lun %d \n",                 hostno, target, lun);        st0x_aborted = DID_ERROR;        fast = 0;#endif        break;}if (fast && transfersize && !(len % transfersize) && (len >= transfersize)#ifdef FAST32	&& !(transfersize % 4)#endif	) {#if (DEBUG & DEBUG_FAST)         printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"               "         len = %d, data = %08x\n", hostno, SCint->underflow,                SCint->transfersize, len, data);#endif        __asm__("	cld;"#ifdef FAST32"	shr $2, %%ecx;1:	lodsl;	movl %%eax, (%%edi);"#else"1:	lodsb;        movb %%al, (%%edi);"#endif"	loop 1b;" : :        /* input */        "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) :        /* clobbered */        "eax", "ecx", "esi" );	len -= transfersize;	data += transfersize;#if (DEBUG & DEBUG_FAST)	printk("scsi%d : FAST transfer complete len = %d data = %08x\n", 		hostno, len, data);#endif} else #endif{/* * 	We loop as long as we are in a data out phase, there is data to send,  *	and BSY is still active. */		__asm__ (/*	Local variables : 	len = ecx	data = esi	st0x_cr_sr = ebx	st0x_dr =  edi	Test for any data here at all.*/	"\torl %%ecx, %%ecx	jz 2f	cld	movl _st0x_cr_sr, %%ebx	movl _st0x_dr, %%edi	1:	movb (%%ebx), %%al\n"/*	Test for BSY*/	"\ttest $1, %%al	jz 2f\n"/*	Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0.*/	"\ttest $0xe, %%al	jnz 2f	\n"/*	Test for REQ*/		"\ttest $0x10, %%al	jz 1b	lodsb	movb %%al, (%%edi) 	loop 1b2: 									":/* output */"=S" (data), "=c" (len) :/* input */"0" (data), "1" (len) :/* clobbered */"eax", "ebx", "edi"); }                        if (!len && nobuffs) {                                --nobuffs;

⌨️ 快捷键说明

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