commsup.c

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

C
1,700
字号
	 *	caller.	 *	 *	Map the hw fib pointer as a 32bit value	 */	hw_fib->header.Command = cpu_to_le16(command);	hw_fib->header.XferState |= cpu_to_le32(SentFromHost);	fibptr->hw_fib_va->header.Flags = 0;	/* 0 the flags field - internal only*/	/*	 *	Set the size of the Fib we want to send to the adapter	 */	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {		return -EMSGSIZE;	}                	/*	 *	Get a queue entry connect the FIB to it and send an notify	 *	the adapter a command is ready.	 */	hw_fib->header.XferState |= cpu_to_le32(NormalPriority);	/*	 *	Fill in the Callback and CallbackContext if we are not	 *	going to wait.	 */	if (!wait) {		fibptr->callback = callback;		fibptr->callback_data = callback_data;	}	fibptr->done = 0;	fibptr->flags = 0;	FIB_COUNTER_INCREMENT(aac_config.FibsSent);	dprintk((KERN_DEBUG "Fib contents:.\n"));	dprintk((KERN_DEBUG "  Command =               %d.\n", le32_to_cpu(hw_fib->header.Command)));	dprintk((KERN_DEBUG "  SubCommand =            %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command)));	dprintk((KERN_DEBUG "  XferState  =            %x.\n", le32_to_cpu(hw_fib->header.XferState)));	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib_va));	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));	if (!dev->queues)		return -EBUSY;	if(wait)		spin_lock_irqsave(&fibptr->event_lock, flags);	aac_adapter_deliver(fibptr);	/*	 *	If the caller wanted us to wait for response wait now. 	 */    	if (wait) {		spin_unlock_irqrestore(&fibptr->event_lock, flags);		/* Only set for first known interruptable command */		if (wait < 0) {			/*			 * *VERY* Dangerous to time out a command, the			 * assumption is made that we have no hope of			 * functioning because an interrupt routing or other			 * hardware failure has occurred.			 */			unsigned long count = 36000000L; /* 3 minutes */			while (down_trylock(&fibptr->event_wait)) {				int blink;				if (--count == 0) {					struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue];					spin_lock_irqsave(q->lock, qflags);					q->numpending--;					spin_unlock_irqrestore(q->lock, qflags);					if (wait == -1) {	        				printk(KERN_ERR "aacraid: aac_fib_send: first asynchronous command timed out.\n"						  "Usually a result of a PCI interrupt routing problem;\n"						  "update mother board BIOS or consider utilizing one of\n"						  "the SAFE mode kernel options (acpi, apic etc)\n");					}					return -ETIMEDOUT;				}				if ((blink = aac_adapter_check_health(dev)) > 0) {					if (wait == -1) {	        				printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n"						  "Usually a result of a serious unrecoverable hardware problem\n",						  blink);					}					return -EFAULT;				}				udelay(5);			}		} else			(void)down_interruptible(&fibptr->event_wait);		spin_lock_irqsave(&fibptr->event_lock, flags);		if (fibptr->done == 0) {			fibptr->done = 2; /* Tell interrupt we aborted */			spin_unlock_irqrestore(&fibptr->event_lock, flags);			return -EINTR;		}		spin_unlock_irqrestore(&fibptr->event_lock, flags);		BUG_ON(fibptr->done == 0);					if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))			return -ETIMEDOUT;		return 0;	}	/*	 *	If the user does not want a response than return success otherwise	 *	return pending	 */	if (reply)		return -EINPROGRESS;	else		return 0;}/**  *	aac_consumer_get	-	get the top of the queue *	@dev: Adapter *	@q: Queue *	@entry: Return entry * *	Will return a pointer to the entry on the top of the queue requested that * 	we are a consumer of, and return the address of the queue entry. It does *	not change the state of the queue.  */int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry){	u32 index;	int status;	if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) {		status = 0;	} else {		/*		 *	The consumer index must be wrapped if we have reached		 *	the end of the queue, else we just use the entry		 *	pointed to by the header index		 */		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 			index = 0;				else		        index = le32_to_cpu(*q->headers.consumer);		*entry = q->base + index;		status = 1;	}	return(status);}/** *	aac_consumer_free	-	free consumer entry *	@dev: Adapter *	@q: Queue *	@qid: Queue ident * *	Frees up the current top of the queue we are a consumer of. If the *	queue was full notify the producer that the queue is no longer full. */void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid){	int wasfull = 0;	u32 notify;	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))		wasfull = 1;        	if (le32_to_cpu(*q->headers.consumer) >= q->entries)		*q->headers.consumer = cpu_to_le32(1);	else		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);        	if (wasfull) {		switch (qid) {		case HostNormCmdQueue:			notify = HostNormCmdNotFull;			break;		case HostNormRespQueue:			notify = HostNormRespNotFull;			break;		default:			BUG();			return;		}		aac_adapter_notify(dev, notify);	}}        /** *	aac_fib_adapter_complete	-	complete adapter issued fib *	@fibptr: fib to complete *	@size: size of fib * *	Will do all necessary work to complete a FIB that was sent from *	the adapter. */int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size){	struct hw_fib * hw_fib = fibptr->hw_fib_va;	struct aac_dev * dev = fibptr->dev;	struct aac_queue * q;	unsigned long nointr = 0;	unsigned long qflags;	if (hw_fib->header.XferState == 0) {		if (dev->comm_interface == AAC_COMM_MESSAGE)			kfree (hw_fib);        	return 0;	}	/*	 *	If we plan to do anything check the structure type first.	 */ 	if ( hw_fib->header.StructType != FIB_MAGIC ) {		if (dev->comm_interface == AAC_COMM_MESSAGE)			kfree (hw_fib);        	return -EINVAL;	}	/*	 *	This block handles the case where the adapter had sent us a	 *	command and we have finished processing the command. We	 *	call completeFib when we are done processing the command 	 *	and want to send a response back to the adapter. This will 	 *	send the completed cdb to the adapter.	 */	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {		if (dev->comm_interface == AAC_COMM_MESSAGE) {			kfree (hw_fib);		} else {	       		u32 index;		        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);			if (size) {				size += sizeof(struct aac_fibhdr);				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 					return -EMSGSIZE;				hw_fib->header.Size = cpu_to_le16(size);			}			q = &dev->queues->queue[AdapNormRespQueue];			spin_lock_irqsave(q->lock, qflags);			aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr);			*(q->headers.producer) = cpu_to_le32(index + 1);			spin_unlock_irqrestore(q->lock, qflags);			if (!(nointr & (int)aac_config.irq_mod))				aac_adapter_notify(dev, AdapNormRespQueue);		}	}	else 	{        	printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n");        	BUG();	}   	return 0;}/** *	aac_fib_complete	-	fib completion handler *	@fib: FIB to complete * *	Will do all necessary work to complete a FIB. */ int aac_fib_complete(struct fib *fibptr){	struct hw_fib * hw_fib = fibptr->hw_fib_va;	/*	 *	Check for a fib which has already been completed	 */	if (hw_fib->header.XferState == 0)        	return 0;	/*	 *	If we plan to do anything check the structure type first.	 */ 	if (hw_fib->header.StructType != FIB_MAGIC)	        return -EINVAL;	/*	 *	This block completes a cdb which orginated on the host and we 	 *	just need to deallocate the cdb or reinit it. At this point the	 *	command is complete that we had sent to the adapter and this	 *	cdb could be reused.	 */	if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) &&		(hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)))	{		fib_dealloc(fibptr);	}	else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost))	{		/*		 *	This handles the case when the host has aborted the I/O		 *	to the adapter because the adapter is not responding		 */		fib_dealloc(fibptr);	} else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) {		fib_dealloc(fibptr);	} else {		BUG();	}   	return 0;}/** *	aac_printf	-	handle printf from firmware *	@dev: Adapter *	@val: Message info * *	Print a message passed to us by the controller firmware on the *	Adaptec board */void aac_printf(struct aac_dev *dev, u32 val){	char *cp = dev->printfbuf;	if (dev->printf_enabled)	{		int length = val & 0xffff;		int level = (val >> 16) & 0xffff;				/*		 *	The size of the printfbuf is set in port.c		 *	There is no variable or define for it		 */		if (length > 255)			length = 255;		if (cp[length] != 0)			cp[length] = 0;		if (level == LOG_AAC_HIGH_ERROR)			printk(KERN_WARNING "%s:%s", dev->name, cp);		else			printk(KERN_INFO "%s:%s", dev->name, cp);	}	memset(cp, 0,  256);}/** *	aac_handle_aif		-	Handle a message from the firmware *	@dev: Which adapter this fib is from *	@fibptr: Pointer to fibptr from adapter * *	This routine handles a driver notify fib from the adapter and *	dispatches it to the appropriate routine for handling. */#define AIF_SNIFF_TIMEOUT	(30*HZ)static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr){	struct hw_fib * hw_fib = fibptr->hw_fib_va;	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;	u32 container;	struct scsi_device *device;	enum {		NOTHING,		DELETE,		ADD,		CHANGE	} device_config_needed;	/* Sniff for container changes */	if (!dev || !dev->fsa_dev)		return;	container = (u32)-1;	/*	 *	We have set this up to try and minimize the number of	 * re-configures that take place. As a result of this when	 * certain AIF's come in we will set a flag waiting for another	 * type of AIF before setting the re-config flag.	 */	switch (le32_to_cpu(aifcmd->command)) {	case AifCmdDriverNotify:		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {		/*		 *	Morph or Expand complete		 */		case AifDenMorphComplete:		case AifDenVolumeExtendComplete:			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);			if (container >= dev->maximum_num_containers)				break;			/*			 *	Find the scsi_device associated with the SCSI			 * address. Make sure we have the right array, and if			 * so set the flag to initiate a new re-config once we			 * see an AifEnConfigChange AIF come through.			 */			if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {				device = scsi_device_lookup(dev->scsi_host_ptr, 					CONTAINER_TO_CHANNEL(container), 					CONTAINER_TO_ID(container), 					CONTAINER_TO_LUN(container));				if (device) {					dev->fsa_dev[container].config_needed = CHANGE;					dev->fsa_dev[container].config_waiting_on = AifEnConfigChange;					dev->fsa_dev[container].config_waiting_stamp = jiffies;					scsi_device_put(device);				}			}		}		/*		 *	If we are waiting on something and this happens to be		 * that thing then set the re-configure flag.		 */		if (container != (u32)-1) {			if (container >= dev->maximum_num_containers)				break;			if ((dev->fsa_dev[container].config_waiting_on ==			    le32_to_cpu(*(u32 *)aifcmd->data)) &&			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))				dev->fsa_dev[container].config_waiting_on = 0;		} else for (container = 0;		    container < dev->maximum_num_containers; ++container) {			if ((dev->fsa_dev[container].config_waiting_on ==			    le32_to_cpu(*(u32 *)aifcmd->data)) &&			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))				dev->fsa_dev[container].config_waiting_on = 0;		}		break;	case AifCmdEventNotify:

⌨️ 快捷键说明

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