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

📄 fas216.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
 *  for new implementations.  The correct method is to respond to an *  SDTR message with a MESSAGE REJECT message if the either the *  initiator or target devices does not support synchronous transfers *  or does not want to negotiate for synchronous transfers at the time. *  Using the correct method assures compatibility with wide data *  transfers and future enhancements. * * We will always initiate a synchronous transfer negotiation request on * every INQUIRY or REQUEST SENSE message, unless the target itself has * at some point performed a synchronous transfer negotiation request, or * we have synchronous transfers disabled for this device. *//** * fas216_handlesync - Handle a synchronous transfer message * @info: state structure for interface * @msg: message from target * * Handle a synchronous transfer message from the target */static void fas216_handlesync(FAS216_Info *info, char *msg){	struct fas216_device *dev = &info->device[info->SCpnt->device->id];	enum { sync, async, none, reject } res = none;#ifdef SCSI2_SYNC	switch (msg[0]) {	case MESSAGE_REJECT:		/* Synchronous transfer request failed.		 * Note: SCSI II r10:		 *		 *  SCSI devices that are capable of synchronous		 *  data transfers shall not respond to an SDTR		 *  message with a MESSAGE REJECT message.		 *		 * Hence, if we get this condition, we disable		 * negotiation for this device.		 */		if (dev->sync_state == neg_inprogress) {			dev->sync_state = neg_invalid;			res = async;		}		break;	case EXTENDED_MESSAGE:		switch (dev->sync_state) {		/* We don't accept synchronous transfer requests.		 * Respond with a MESSAGE_REJECT to prevent a		 * synchronous transfer agreement from being reached.		 */		case neg_invalid:			res = reject;			break;		/* We were not negotiating a synchronous transfer,		 * but the device sent us a negotiation request.		 * Honour the request by sending back a SDTR		 * message containing our capability, limited by		 * the targets capability.		 */		default:			fas216_cmd(info, CMD_SETATN);			if (msg[4] > info->ifcfg.sync_max_depth)				msg[4] = info->ifcfg.sync_max_depth;			if (msg[3] < 1000 / info->ifcfg.clockrate)				msg[3] = 1000 / info->ifcfg.clockrate;			msgqueue_flush(&info->scsi.msgs);			msgqueue_addmsg(&info->scsi.msgs, 5,					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,					msg[3], msg[4]);			info->scsi.phase = PHASE_MSGOUT_EXPECT;			/* This is wrong.  The agreement is not in effect			 * until this message is accepted by the device			 */			dev->sync_state = neg_targcomplete;			res = sync;			break;		/* We initiated the synchronous transfer negotiation,		 * 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[4] <= info->ifcfg.sync_max_depth &&			    msg[3] >= 1000 / info->ifcfg.clockrate) {				dev->sync_state = neg_complete;				res = sync;			}			break;		}	}#else	res = reject;#endif	switch (res) {	case sync:		dev->period = msg[3];		dev->sof    = msg[4];		dev->stp    = fas216_syncperiod(info, msg[3] * 4);		fas216_set_sync(info, info->SCpnt->device->id);		break;	case reject:		fas216_cmd(info, CMD_SETATN);		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->device->id);		break;	case none:		break;	}}/** * fas216_updateptrs - update data pointers after transfer suspended/paused * @info: interface's local pointer to update * @bytes_transferred: number of bytes transferred * * Update data pointers after transfer suspended/paused */static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred){	struct scsi_pointer *SCp = &info->scsi.SCp;	fas216_checkmagic(info);	BUG_ON(bytes_transferred < 0);	info->SCpnt->request_bufflen -= bytes_transferred;	while (bytes_transferred != 0) {		if (SCp->this_residual > bytes_transferred)			break;		/*		 * We have used up this buffer.  Move on to the		 * next buffer.		 */		bytes_transferred -= SCp->this_residual;		if (!next_SCp(SCp) && bytes_transferred) {			printk(KERN_WARNING "scsi%d.%c: out of buffers\n",				info->host->host_no, '0' + info->SCpnt->device->id);			return;		}	}	SCp->this_residual -= bytes_transferred;	if (SCp->this_residual)		SCp->ptr += bytes_transferred;	else		SCp->ptr = NULL;}/** * fas216_pio - transfer data off of/on to card using programmed IO * @info: interface to transfer data to/from * @direction: direction to transfer data (DMA_OUT/DMA_IN) * * Transfer data off of/on to card using programmed IO. * Notes: this is incredibly slow. */static void fas216_pio(FAS216_Info *info, fasdmadir_t direction){	struct scsi_pointer *SCp = &info->scsi.SCp;	fas216_checkmagic(info);	if (direction == DMA_OUT)		fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp));	else		put_next_SCp_byte(SCp, fas216_readb(info, REG_FF));	if (SCp->this_residual == 0)		next_SCp(SCp);}static void fas216_set_stc(FAS216_Info *info, unsigned int length){	fas216_writeb(info, REG_STCL, length);	fas216_writeb(info, REG_STCM, length >> 8);	fas216_writeb(info, REG_STCH, length >> 16);}static unsigned int fas216_get_ctc(FAS216_Info *info){	return fas216_readb(info, REG_CTCL) +	       (fas216_readb(info, REG_CTCM) << 8) +	       (fas216_readb(info, REG_CTCH) << 16);}/** * fas216_cleanuptransfer - clean up after a transfer has completed. * @info: interface to clean up * * Update the data pointers according to the number of bytes transferred * on the SCSI bus. */static void fas216_cleanuptransfer(FAS216_Info *info){	unsigned long total, residual, fifo;	fasdmatype_t dmatype = info->dma.transfer_type;	info->dma.transfer_type = fasdma_none;	/*	 * PIO transfers do not need to be cleaned up.	 */	if (dmatype == fasdma_pio || dmatype == fasdma_none)		return;	if (dmatype == fasdma_real_all)		total = info->SCpnt->request_bufflen;	else		total = info->scsi.SCp.this_residual;	residual = fas216_get_ctc(info);	fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;	fas216_log(info, LOG_BUFFER, "cleaning up from previous "		   "transfer: length 0x%06x, residual 0x%x, fifo %d",		   total, residual, fifo);	/*	 * If we were performing Data-Out, the transfer counter	 * counts down each time a byte is transferred by the	 * host to the FIFO.  This means we must include the	 * bytes left in the FIFO from the transfer counter.	 */	if (info->scsi.phase == PHASE_DATAOUT)		residual += fifo;	fas216_updateptrs(info, total - residual);}/** * fas216_transfer - Perform a DMA/PIO transfer off of/on to card * @info: interface from which device disconnected from * * Start a DMA/PIO transfer off of/on to card */static void fas216_transfer(FAS216_Info *info){	fasdmadir_t direction;	fasdmatype_t dmatype;	fas216_log(info, LOG_BUFFER,		   "starttransfer: buffer %p length 0x%06x reqlen 0x%06x",		   info->scsi.SCp.ptr, info->scsi.SCp.this_residual,		   info->SCpnt->request_bufflen);	if (!info->scsi.SCp.ptr) {		fas216_log(info, LOG_ERROR, "null buffer passed to "			   "fas216_starttransfer");		print_SCp(&info->scsi.SCp, "SCp: ", "\n");		print_SCp(&info->SCpnt->SCp, "Cmnd SCp: ", "\n");		return;	}	/*	 * If we have a synchronous transfer agreement in effect, we must	 * use DMA mode.  If we are using asynchronous transfers, we may	 * use DMA mode or PIO mode.	 */	if (info->device[info->SCpnt->device->id].sof)		dmatype = fasdma_real_all;	else		dmatype = fasdma_pio;	if (info->scsi.phase == PHASE_DATAOUT)		direction = DMA_OUT;	else		direction = DMA_IN;	if (info->dma.setup)		dmatype = info->dma.setup(info->host, &info->scsi.SCp,					  direction, dmatype);	info->dma.transfer_type = dmatype;	if (dmatype == fasdma_real_all)		fas216_set_stc(info, info->SCpnt->request_bufflen);	else		fas216_set_stc(info, info->scsi.SCp.this_residual);	switch (dmatype) {	case fasdma_pio:		fas216_log(info, LOG_BUFFER, "PIO transfer");		fas216_writeb(info, REG_SOF, 0);		fas216_writeb(info, REG_STP, info->scsi.async_stp);		fas216_cmd(info, CMD_TRANSFERINFO);		fas216_pio(info, direction);		break;	case fasdma_pseudo:		fas216_log(info, LOG_BUFFER, "pseudo transfer");		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);		info->dma.pseudo(info->host, &info->scsi.SCp,				 direction, info->SCpnt->transfersize);		break;	case fasdma_real_block:		fas216_log(info, LOG_BUFFER, "block dma transfer");		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);		break;	case fasdma_real_all:		fas216_log(info, LOG_BUFFER, "total dma transfer");		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);		break;	default:		fas216_log(info, LOG_BUFFER | LOG_ERROR,			   "invalid FAS216 DMA type");		break;	}}/** * fas216_stoptransfer - Stop a DMA transfer onto / off of the card * @info: interface from which device disconnected from * * Called when we switch away from DATA IN or DATA OUT phases. */static void fas216_stoptransfer(FAS216_Info *info){	fas216_checkmagic(info);	if (info->dma.transfer_type == fasdma_real_all ||	    info->dma.transfer_type == fasdma_real_block)		info->dma.stop(info->host, &info->scsi.SCp);	fas216_cleanuptransfer(info);	if (info->scsi.phase == PHASE_DATAIN) {		unsigned int fifo;		/*		 * If we were performing Data-In, then the FIFO counter		 * contains the number of bytes not transferred via DMA		 * from the on-board FIFO.  Read them manually.		 */		fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;		while (fifo && info->scsi.SCp.ptr) {			*info->scsi.SCp.ptr = fas216_readb(info, REG_FF);			fas216_updateptrs(info, 1);			fifo--;		}	} else {		/*		 * After a Data-Out phase, there may be unsent		 * bytes left in the FIFO.  Flush them out.		 */		fas216_cmd(info, CMD_FLUSHFIFO);	}}static void fas216_aborttransfer(FAS216_Info *info){	fas216_checkmagic(info);	if (info->dma.transfer_type == fasdma_real_all ||	    info->dma.transfer_type == fasdma_real_block)		info->dma.stop(info->host, &info->scsi.SCp);	info->dma.transfer_type = fasdma_none;	fas216_cmd(info, CMD_FLUSHFIFO);}static void fas216_kick(FAS216_Info *info);/** * fas216_disconnected_intr - handle device disconnection * @info: interface from which device disconnected from * * Handle device disconnection */static void fas216_disconnect_intr(FAS216_Info *info){	unsigned long flags;	fas216_checkmagic(info);	fas216_log(info, LOG_CONNECT, "disconnect phase=%02x",		   info->scsi.phase);	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		*/		info->scsi.disconnectable = 1;		info->scsi.phase = PHASE_IDLE;		info->stats.disconnects += 1;		spin_lock_irqsave(&info->host_lock, flags);		if (info->scsi.phase == PHASE_IDLE)			fas216_kick(info);		spin_unlock_irqrestore(&info->host_lock, flags);		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;	}}/** * fas216_reselected_intr - start reconnection of a device * @info: interface which was reselected * * Start reconnection of a device */static voidfas216_reselected_intr(FAS216_Info *info){	unsigned int cfis, i;	unsigned char msg[4];	unsigned char target, lun, tag;	fas216_checkmagic(info);	WARN_ON(info->scsi.phase == PHASE_SELECTION ||		info->scsi.phase == PHASE_SELSTEPS);	cfis = fas216_readb(info, REG_CFIS);	fas216_log(info, LOG_CONNECT, "reconnect phase=%02x cfis=%02x",		   info->scsi.phase, cfis);	cfis &= CFIS_CF;	if (cfis < 2 || cfis > 4) {		printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",			info->host->host_no);		goto bad_message;	}	for (i = 0; i < cfis; i++)		msg[i] = fas216_readb(info, REG_FF);	if (!(msg[0] & (1 << info->host->this_id)) ||	    !(msg[1] & 0x80))		goto initiator_error;	target = msg[0] & ~(1 << info->host->this_id);	target = ffs(target) - 1;	lun = msg[1] & 7;	tag = 0;	if (cfis >= 3) {		if (msg[2] != SIMPLE_QUEUE_TAG)			goto initiator_error;		tag = msg[3];	}	/* set up for synchronous transfers */	fas216_writeb(info, REG_SDID, target);	fas216_set_sync(info, target);	msgqueue_flush(&info->scsi.msgs);	fas216_log(info, LOG_CONNECT, "Reconnected: target %1x lun %1x tag %02x",		   target, lun, tag);	if (info->scsi.disconnectable && info->SCpnt) {

⌨️ 快捷键说明

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