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

📄 i2o_scsi.c

📁 MIZI Research, Inc.发布的嵌入式Linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		if(sg_chain_pool!=NULL)		{			kfree(sg_chain_pool);			sg_chain_pool = NULL;		}		flush_pending();		del_timer(&retry_timer);		i2o_remove_handler(&i2o_scsi_handler);	}		return count;}int i2o_scsi_release(struct Scsi_Host *host){	if(--i2o_scsi_hosts==0)	{		if(sg_chain_pool!=NULL)		{			kfree(sg_chain_pool);			sg_chain_pool = NULL;		}		flush_pending();		del_timer(&retry_timer);		i2o_remove_handler(&i2o_scsi_handler);	}	return 0;}const char *i2o_scsi_info(struct Scsi_Host *SChost){	struct i2o_scsi_host *hostdata;	hostdata = (struct i2o_scsi_host *)SChost->hostdata;	return(&hostdata->controller->name[0]);}/* * From the wd93 driver: * Returns true if there will be a DATA_OUT phase with this command,  * false otherwise. * (Thanks to Joerg Dorchain for the research and suggestion.) * */static int is_dir_out(Scsi_Cmnd *cmd){	switch (cmd->cmnd[0]) 	{     		case WRITE_6:           case WRITE_10:          case WRITE_12:      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:      		case WRITE_VERIFY:      case WRITE_VERIFY_12:            		case COMPARE:           case COPY:              case COPY_VERIFY:      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:            		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:      		case 0xea:        		return 1;		default:        		return 0;	}}int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)){	int i;	int tid;	struct i2o_controller *c;	Scsi_Cmnd *current_command;	struct Scsi_Host *host;	struct i2o_scsi_host *hostdata;	u32 *msg, *mptr;	u32 m;	u32 *lenptr;	int direction;	int scsidir;	u32 len;	u32 reqlen;	u32 tag;		static int max_qd = 1;		/*	 *	Do the incoming paperwork	 */	 	host = SCpnt->host;	hostdata = (struct i2o_scsi_host *)host->hostdata;	 	c = hostdata->controller;	prefetch(c);	prefetchw(&queue_depth);	SCpnt->scsi_done = done;		if(SCpnt->target > 15)	{		printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target);		return -1;	}		tid = hostdata->task[SCpnt->target][SCpnt->lun];		dprintk(("qcmd: Tid = %d\n", tid));		current_command = SCpnt;		/* set current command                */	current_command->scsi_done = done;	/* set ptr to done function           */	/* We don't have such a device. Pretend we did the command 	   and that selection timed out */		if(tid == -1)	{		SCpnt->result = DID_NO_CONNECT << 16;		done(SCpnt);		return 0;	}		dprintk(("Real scsi messages.\n"));		/*	 *	Obtain an I2O message. Right now we _have_ to obtain one	 *	until the scsi layer stuff is cleaned up.	 */		 	do	{		mb();		m = I2O_POST_READ32(c);	}	while(m==0xFFFFFFFF);	msg = (u32 *)(c->mem_offset + m);		/*	 *	Put together a scsi execscb message	 */		len = SCpnt->request_bufflen;	direction = 0x00000000;			// SGL IN  (osm<--iop)		/*	 *	The scsi layer should be handling this stuff	 */		scsidir = 0x00000000;			// DATA NO XFER	if(len)	{		if(is_dir_out(SCpnt))		{			direction=0x04000000;	// SGL OUT  (osm-->iop)			scsidir  =0x80000000;	// DATA OUT (iop-->dev)		}		else		{			scsidir  =0x40000000;	// DATA IN  (iop<--dev)		}	}		__raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);	__raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */	/* Sorry 64bit folks. FIXME */	__raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */	/* LSI_920_PCI_QUIRK	 *	 *	Intermittant observations of msg frame word data corruption	 *	observed on msg[4] after:	 *	  WRITE, READ-MODIFY-WRITE	 *	operations.  19990606 -sralston	 *	 *	(Hence we build this word via tag. Its good practice anyway	 *	 we don't want fetches over PCI needlessly)	 */	tag=0;		/*	 *	Attach tags to the devices	 */		if(SCpnt->device->tagged_supported)	{		/*		 *	Some drives are too stupid to handle fairness issues		 *	with tagged queueing. We throw in the odd ordered		 *	tag to stop them starving themselves.		 */		if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))		{			tag=0x01800000;		/* ORDERED! */			hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;		}		else		{			/* Hmmm...  I always see value of 0 here,			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston			 */			if(SCpnt->tag == HEAD_OF_QUEUE_TAG)				tag=0x01000000;			else if(SCpnt->tag == ORDERED_QUEUE_TAG)				tag=0x01800000;		}	}	/* Direction, disconnect ok, tag, CDBLen */	__raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);	mptr=msg+5;	/* 	 *	Write SCSI command into the message - always 16 byte block 	 */	 	memcpy_toio(mptr, SCpnt->cmnd, 16);	mptr+=4;	lenptr=mptr++;		/* Remember me - fill in when we know */		reqlen = 12;		// SINGLE SGE		/*	 *	Now fill in the SGList and command 	 *	 *	FIXME: we need to set the sglist limits according to the 	 *	message size of the I2O controller. We might only have room	 *	for 6 or so worst case	 */		if(SCpnt->use_sg)	{		struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;		int chain = 0;				len = 0;		if((sg_max_frags > 11) && (SCpnt->use_sg > 11))		{			chain = 1;			/*			 *	Need to chain!			 */			__raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);			__raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);			mptr = (u32*)(sg_chain_pool + sg_chain_tag);			if (SCpnt->use_sg > max_sg_len)			{				max_sg_len = SCpnt->use_sg;				printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",					SCpnt, SCpnt->use_sg, sg_chain_tag);			}			if ( ++sg_chain_tag == SG_MAX_BUFS )				sg_chain_tag = 0;			for(i = 0 ; i < SCpnt->use_sg; i++)			{				*mptr++=direction|0x10000000|sg->length;				len+=sg->length;				*mptr++=virt_to_bus(sg->address);				sg++;			}			mptr[-2]=direction|0xD0000000|(sg-1)->length;		}		else		{					for(i = 0 ; i < SCpnt->use_sg; i++)			{				__raw_writel(direction|0x10000000|sg->length, mptr++);				len+=sg->length;				__raw_writel(virt_to_bus(sg->address), mptr++);				sg++;			}			/* Make this an end of list. Again evade the 920 bug and			   unwanted PCI read traffic */					__raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);		}				if(!chain)			reqlen = mptr - msg;				__raw_writel(len, lenptr);				if(len != SCpnt->underflow)			printk("Cmd len %08X Cmd underflow %08X\n",				len, SCpnt->underflow);	}	else	{		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,				SCpnt->request_bufflen));		__raw_writel(len = SCpnt->request_bufflen, lenptr);		if(len == 0)		{			reqlen = 9;		}		else		{			__raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);			__raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);		}	}		/*	 *	Stick the headers on 	 */	__raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);		/* Queue the message */	i2o_post_message(c,m);		atomic_inc(&queue_depth);		if(atomic_read(&queue_depth)> max_qd)	{		max_qd=atomic_read(&queue_depth);		printk("Queue depth now %d.\n", max_qd);	}		mb();	dprintk(("Issued %ld\n", current_command->serial_number));		return 0;}static void internal_done(Scsi_Cmnd * SCpnt){	SCpnt->SCp.Status++;}int i2o_scsi_command(Scsi_Cmnd * SCpnt){	i2o_scsi_queuecommand(SCpnt, internal_done);	SCpnt->SCp.Status = 0;	while (!SCpnt->SCp.Status)		barrier();	return SCpnt->result;}int i2o_scsi_abort(Scsi_Cmnd * SCpnt){	struct i2o_controller *c;	struct Scsi_Host *host;	struct i2o_scsi_host *hostdata;	u32 *msg;	u32 m;	int tid;		printk("i2o_scsi: Aborting command block.\n");		host = SCpnt->host;	hostdata = (struct i2o_scsi_host *)host->hostdata;	tid = hostdata->task[SCpnt->target][SCpnt->lun];	if(tid==-1)	{		printk(KERN_ERR "impossible command to abort.\n");		return SCSI_ABORT_NOT_RUNNING;	}	c = hostdata->controller;		/*	 *	Obtain an I2O message. Right now we _have_ to obtain one	 *	until the scsi layer stuff is cleaned up.	 */		 	do	{		mb();		m = I2O_POST_READ32(c);	}	while(m==0xFFFFFFFF);	msg = (u32 *)(c->mem_offset + m);		__raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]);	__raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);	__raw_writel(scsi_context, &msg[2]);	__raw_writel(0, &msg[3]);	/* Not needed for an abort */	__raw_writel((u32)SCpnt, &msg[4]);		wmb();	i2o_post_message(c,m);	wmb();	return SCSI_ABORT_PENDING;}int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags){	int tid;	struct i2o_controller *c;	struct Scsi_Host *host;	struct i2o_scsi_host *hostdata;	u32 m;	u32 *msg;	/*	 *	Find the TID for the bus	 */	printk("i2o_scsi: Attempting to reset the bus.\n");		host = SCpnt->host;	hostdata = (struct i2o_scsi_host *)host->hostdata;	tid = hostdata->bus_task;	c = hostdata->controller;	/*	 *	Now send a SCSI reset request. Any remaining commands	 *	will be aborted by the IOP. We need to catch the reply	 *	possibly ?	 */	 	m = I2O_POST_READ32(c);		/*	 *	No free messages, try again next time - no big deal	 */	 	if(m == 0xFFFFFFFF)		return SCSI_RESET_PUNT;		msg = (u32 *)(c->mem_offset + m);	__raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);	__raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);	__raw_writel(scsi_context|0x80000000, &msg[2]);	/* We use the top bit to split controller and unit transactions */	/* Now store unit,tid so we can tie the completion back to a specific device */	__raw_writel(c->unit << 16 | tid, &msg[3]);	wmb();	i2o_post_message(c,m);	return SCSI_RESET_PENDING;}/* *	This is anyones guess quite frankly. */ int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip){	int size;	size = disk->capacity;	ip[0] = 64;		/* heads                        */	ip[1] = 32;		/* sectors                      */	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */		ip[0] = 255;	/* heads                        */		ip[1] = 63;	/* sectors                      */		ip[2] = size / (255 * 63);	/* cylinders                    */	}	return 0;}MODULE_AUTHOR("Red Hat Software");MODULE_LICENSE("GPL");static Scsi_Host_Template driver_template = I2OSCSI;#include "../../scsi/scsi_module.c"

⌨️ 快捷键说明

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