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

📄 fas216.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
		break;	case reject:		outb(CMD_SETATN, REG_CMD(info));		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);		info->scsi.phase = PHASE_MSGOUT_EXPECT;	case async:		dev->period = info->ifcfg.asyncperiod / 4;		dev->sof    = 0;		dev->stp    = info->scsi.async_stp;		fas216_set_sync(info, info->SCpnt->target);		break;	case none:		break;	}}/* Function: void fas216_handlewide(FAS216_Info *info, char *msg) * Purpose : Handle a wide transfer message from the target * Params  : info - state structure for interface *         : msg  - message from target */static voidfas216_handlewide(FAS216_Info *info, char *msg){	struct fas216_device *dev = &info->device[info->SCpnt->target];	enum { wide, bit8, none, reject } res = none;#ifdef SCSI2_WIDE	switch (msg[0]) {	case MESSAGE_REJECT:		/* Wide transfer request failed.		 * Note: SCSI II r10:		 *		 *  SCSI devices that are capable of wide		 *  data transfers shall not respond to a		 *  WDTR message with a MESSAGE REJECT message.		 *		 * Hence, if we get this condition, we never		 * reattempt negociation for this device.		 */		if (dev->wide_state == neg_inprogress) {			dev->wide_state = neg_invalid;			res = bit8;		}		break;	case EXTENDED_MESSAGE:		switch (dev->wide_state) {		/* We don't accept wide data transfer requests.		 * Respond with a MESSAGE REJECT to prevent a		 * wide data transfer agreement from being reached.		 */		case neg_invalid:			res = reject;			break;		/* We were not negociating a wide data transfer,		 * but the device sent is a negociation request.		 * Honour the request by sending back a WDTR		 * message containing our capability, limited by		 * the targets capability.		 */		default:			outb(CMD_SETATN, REG_CMD(info));			if (msg[3] > info->ifcfg.wide_max_size)				msg[3] = info->ifcfg.wide_max_size;			msgqueue_flush(&info->scsi.msgs);			msgqueue_addmsg(&info->scsi.msgs, 4,					EXTENDED_MESSAGE, 2, EXTENDED_WDTR,					msg[3]);			info->scsi.phase = PHASE_MSGOUT_EXPECT;			res = wide;			break;		/* We initiated the wide data transfer negociation,		 * and have successfully received a response from the		 * target.  The synchronous transfer agreement has been		 * reached.  Note: if the values returned are out of our		 * bounds, we must reject the message.		 */		case neg_inprogress:			res = reject;			if (msg[3] <= info->ifcfg.wide_max_size) {				dev->wide_state = neg_complete;				res = wide;			}			break;		}	}#else	res = reject;#endif	switch (res) {	case wide:		dev->wide_xfer = msg[3];		break;	case reject:		outb(CMD_SETATN, REG_CMD(info));		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);		info->scsi.phase = PHASE_MSGOUT_EXPECT;	case bit8:		dev->wide_xfer = 0;		break;	case none:		break;	}}/* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * Purpose : update data pointers after transfer suspended/paused * Params  : info              - interface's local pointer to update *           bytes_transferred - number of bytes transferred */static voidfas216_updateptrs(FAS216_Info *info, int bytes_transferred){	unsigned char *ptr;	unsigned int residual;	fas216_checkmagic(info);	ptr = info->scsi.SCp.ptr;	residual = info->scsi.SCp.this_residual;	info->SCpnt->request_bufflen -= bytes_transferred;	while (residual <= bytes_transferred && bytes_transferred) {		/* We have used up this buffer */		bytes_transferred -= residual;		if (info->scsi.SCp.buffers_residual) {			info->scsi.SCp.buffer++;			info->scsi.SCp.buffers_residual--;			ptr = (unsigned char *)info->scsi.SCp.buffer->address;			residual = info->scsi.SCp.buffer->length;		} else {			ptr = NULL;			residual = 0;		}	}	residual -= bytes_transferred;	ptr += bytes_transferred;	if (residual == 0)		ptr = NULL;	info->scsi.SCp.ptr = ptr;	info->scsi.SCp.this_residual = residual;}/* Function: void fas216_pio(FAS216_Info *info, fasdmadir_t direction) * Purpose : transfer data off of/on to card using programmed IO * Params  : info      - interface to transfer data to/from *           direction - direction to transfer data (DMA_OUT/DMA_IN) * Notes   : this is incredibly slow */static voidfas216_pio(FAS216_Info *info, fasdmadir_t direction){	unsigned int residual;	char *ptr;	fas216_checkmagic(info);	residual = info->scsi.SCp.this_residual;	ptr = info->scsi.SCp.ptr;	if (direction == DMA_OUT)		outb(*ptr++, REG_FF(info));	else		*ptr++ = inb(REG_FF(info));	residual -= 1;	if (residual == 0) {		if (info->scsi.SCp.buffers_residual) {			info->scsi.SCp.buffer++;			info->scsi.SCp.buffers_residual--;			ptr = (unsigned char *)info->scsi.SCp.buffer->address;			residual = info->scsi.SCp.buffer->length;		} else {			ptr = NULL;			residual = 0;		}	}	info->scsi.SCp.ptr = ptr;	info->scsi.SCp.this_residual = residual;}/* Function: void fas216_starttransfer(FAS216_Info *info, *				       fasdmadir_t direction) * Purpose : Start a DMA/PIO transfer off of/on to card * Params  : info      - interface from which device disconnected from *           direction - transfer direction (DMA_OUT/DMA_IN) */static voidfas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo){	fasdmatype_t dmatype;	fas216_checkmagic(info);	info->scsi.phase = (direction == DMA_OUT) ?				PHASE_DATAOUT : PHASE_DATAIN;	if (info->dma.transfer_type != fasdma_none &&	    info->dma.transfer_type != fasdma_pio) {		unsigned long total, residual;		if (info->dma.transfer_type == fasdma_real_all)			total = info->SCpnt->request_bufflen;		else			total = info->scsi.SCp.this_residual;		residual = (inb(REG_CFIS(info)) & CFIS_CF) +			    inb(REG_CTCL(info)) +			    (inb(REG_CTCM(info)) << 8) +			    (inb(REG_CTCH(info)) << 16);		fas216_updateptrs(info, total - residual);	}	info->dma.transfer_type = fasdma_none;	if (!info->scsi.SCp.ptr) {		printk("scsi%d.%c: null buffer passed to "			"fas216_starttransfer\n", info->host->host_no,			fas216_target(info));		return;	}	/* flush FIFO */	if (flush_fifo)		outb(CMD_FLUSHFIFO, REG_CMD(info));	/*	 * Default to PIO mode or DMA mode if we have a synchronous	 * transfer agreement.	 */	if (info->device[info->SCpnt->target].sof && info->dma.setup)		dmatype = fasdma_real_all;	else		dmatype = fasdma_pio;	if (info->dma.setup)		dmatype = info->dma.setup(info->host, &info->scsi.SCp,					  direction, dmatype);	info->dma.transfer_type = dmatype;	switch (dmatype) {	case fasdma_pio:		outb(0, REG_SOF(info));		outb(info->scsi.async_stp, REG_STP(info));		outb(info->scsi.SCp.this_residual, REG_STCL(info));		outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));		outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));		outb(CMD_TRANSFERINFO, REG_CMD(info));		fas216_pio(info, direction);		break;	case fasdma_pseudo:		outb(info->scsi.SCp.this_residual, REG_STCL(info));		outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));		outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));		outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));		info->dma.pseudo(info->host, &info->scsi.SCp,				 direction, info->SCpnt->transfersize);		break;	case fasdma_real_block:		outb(info->scsi.SCp.this_residual, REG_STCL(info));		outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));		outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));		outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));		break;	case fasdma_real_all:		outb(info->SCpnt->request_bufflen, REG_STCL(info));		outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info));		outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info));		outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));		break;	default:		printk(KERN_ERR "scsi%d.%d: invalid FAS216 DMA type\n",		       info->host->host_no, fas216_target(info));		break;	}}/* Function: void fas216_stoptransfer(FAS216_Info *info) * Purpose : Stop a DMA transfer onto / off of the card * Params  : info      - interface from which device disconnected from */static voidfas216_stoptransfer(FAS216_Info *info){	fas216_checkmagic(info);	if (info->dma.transfer_type != fasdma_none &&	    info->dma.transfer_type != fasdma_pio) {		unsigned long total, residual;		if ((info->dma.transfer_type == fasdma_real_all ||		     info->dma.transfer_type == fasdma_real_block) &&		    info->dma.stop)			info->dma.stop(info->host, &info->scsi.SCp);		if (info->dma.transfer_type == fasdma_real_all)			total = info->SCpnt->request_bufflen;		else			total = info->scsi.SCp.this_residual;		residual = (inb(REG_CFIS(info)) & CFIS_CF) +			    inb(REG_CTCL(info)) +			    (inb(REG_CTCM(info)) << 8) +			    (inb(REG_CTCH(info)) << 16);		fas216_updateptrs(info, total - residual);		info->dma.transfer_type = fasdma_none;	}	if (info->scsi.phase == PHASE_DATAOUT)		outb(CMD_FLUSHFIFO, REG_CMD(info));}/* Function: void fas216_disconnected_intr(FAS216_Info *info) * Purpose : handle device disconnection * Params  : info - interface from which device disconnected from */static voidfas216_disconnect_intr(FAS216_Info *info){	fas216_checkmagic(info);#ifdef DEBUG_CONNECT	printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no,		fas216_target(info), info->scsi.phase);#endif	msgqueue_flush(&info->scsi.msgs);	switch (info->scsi.phase) {	case PHASE_SELECTION:			/* while selecting - no target		*/	case PHASE_SELSTEPS:		fas216_done(info, DID_NO_CONNECT);		break;	case PHASE_MSGIN_DISCONNECT:		/* message in - disconnecting		*/		outb(CMD_ENABLESEL, REG_CMD(info));		info->scsi.disconnectable = 1;		info->scsi.reconnected.tag = 0;		info->scsi.phase = PHASE_IDLE;		info->stats.disconnects += 1;		break;	case PHASE_DONE:			/* at end of command - complete		*/		fas216_done(info, DID_OK);		break;	case PHASE_MSGOUT:			/* message out - possible ABORT message	*/		if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {			info->scsi.aborting = 0;			fas216_done(info, DID_ABORT);			break;		}	default:				/* huh?					*/		printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",			info->host->host_no, fas216_target(info), fas216_drv_phase(info));		print_debug_list();		fas216_stoptransfer(info);		fas216_done(info, DID_ERROR);		break;	}}/* Function: void fas216_reselected_intr(FAS216_Info *info) * Purpose : Start reconnection of a device * Params  : info - interface which was reselected */static voidfas216_reselected_intr(FAS216_Info *info){	unsigned char target, identify_msg, ok;	fas216_checkmagic(info);	if ((info->scsi.phase == PHASE_SELECTION ||	     info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {		Scsi_Cmnd *SCpnt = info->SCpnt;		info->origSCpnt = SCpnt;		info->SCpnt = NULL;		if (info->device[SCpnt->target].wide_state == neg_inprogress)			info->device[SCpnt->target].wide_state = neg_wait;		if (info->device[SCpnt->target].sync_state == neg_inprogress)			info->device[SCpnt->target].sync_state = neg_wait;	}#ifdef DEBUG_CONNECT	printk("scsi%d.%c: reconnect phase=%02X\n", info->host->host_no,		fas216_target(info), info->scsi.phase);#endif	if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) {		printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",			info->host->host_no);		outb(CMD_SETATN, REG_CMD(info));		outb(CMD_MSGACCEPTED, REG_CMD(info));		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		return;	}	target = inb(REG_FF(info));	identify_msg = inb(REG_FF(info));	ok = 1;	if (!(target & (1 << info->host->this_id))) {		printk(KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no);		ok = 0;	}	if (!(identify_msg & 0x80)) {		printk(KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n",			info->host->host_no, identify_msg);		ok = 0;	}	if (!ok) {		/*		 * Something went wrong - send an initiator error to		 * the target.		 */		outb(CMD_SETATN, REG_CMD(info));		outb(CMD_MSGACCEPTED, REG_CMD(info));		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		return;	}	target &= ~(1 << info->host->this_id);	switch (target) {	case   1:  target = 0; break;	case   2:  target = 1; break;	case   4:  target = 2; break;	case   8:  target = 3; break;	case  16:  target = 4; break;	case  32:  target = 5; break;	case  64:  target = 6; break;	case 128:  target = 7; break;	default:   target = info->host->this_id; break;	}

⌨️ 快捷键说明

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