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

📄 3w-xxxx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment physical address.\n");		return 1;	}	command_packet->byte8.param.sgl[0].address = param_value;	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);	/* Now drain the controller's aen queue */	do {		/* Post command packet */		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));		/* Now poll for completion */		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {			response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));			request_id = TW_RESID_OUT(response_queue.response_id);			if (request_id != 0) {				/* Unexpected request id */				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");				return 1;			}						if (command_packet->status != 0) {				if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {					/* Bad response */					tw_decode_sense(tw_dev, request_id, 0);					return 1;				} else {					/* We know this is a 3w-1x00, and doesn't support aen's */					return 0;				}			}			/* Now check the aen */			aen = *(unsigned short *)(param->data);			aen_code = (aen & 0x0ff);			queue = 0;			switch (aen_code) {				case TW_AEN_QUEUE_EMPTY:					dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);					if (first_reset != 1) {						return 1;					} else {						finished = 1;					}					break;				case TW_AEN_SOFT_RESET:					if (first_reset == 0) {						first_reset = 1;					} else {						printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);						tw_dev->aen_count++;						queue = 1;					}					break;				default:					if (aen == 0x0ff) {						printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");					} else {						table_max = ARRAY_SIZE(tw_aen_string);						if ((aen & 0x0ff) < table_max) {							if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {								printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);							} else {								printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);							}						} else							printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);					}					tw_dev->aen_count++;					queue = 1;			}			/* Now put the aen on the aen_queue */			if (queue == 1) {				tw_dev->aen_queue[tw_dev->aen_tail] = aen;				if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {					tw_dev->aen_tail = TW_Q_START;				} else {					tw_dev->aen_tail = tw_dev->aen_tail + 1;				}				if (tw_dev->aen_head == tw_dev->aen_tail) {					if (tw_dev->aen_head == TW_Q_LENGTH - 1) {						tw_dev->aen_head = TW_Q_START;					} else {						tw_dev->aen_head = tw_dev->aen_head + 1;					}				}			}			found = 1;		}		if (found == 0) {			printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");			return 1;		}	} while (finished == 0);	return 0;} /* End tw_aen_drain_queue() *//* This function will allocate memory */static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which){	int i;	dma_addr_t dma_handle;	unsigned long *cpu_addr = NULL;	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);	if (cpu_addr == NULL) {		printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");		return 1;	}	if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);		return 1;	}	memset(cpu_addr, 0, size*TW_Q_LENGTH);	for (i=0;i<TW_Q_LENGTH;i++) {		switch(which) {		case 0:			tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);			tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));			break;		case 1:			tw_dev->alignment_physical_address[i] = dma_handle+(i*size);			tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));			break;		default:			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");			return 1;		}	}	return 0;} /* End tw_allocate_memory() *//* This function handles ioctl for the character device */static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	int request_id;	dma_addr_t dma_handle;	unsigned short tw_aen_code;	unsigned long flags;	unsigned int data_buffer_length = 0;	unsigned long data_buffer_length_adjusted = 0;	unsigned long *cpu_addr;	long timeout;	TW_New_Ioctl *tw_ioctl;	TW_Passthru *passthru;	TW_Device_Extension *tw_dev = tw_device_extension_list[iminor(inode)];	int retval = -EFAULT;	void __user *argp = (void __user *)arg;	dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");	/* Only let one of these through at a time */	if (mutex_lock_interruptible(&tw_dev->ioctl_lock))		return -EINTR;	/* First copy down the buffer length */	if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int)))		goto out;	/* Check size */	if (data_buffer_length > TW_MAX_IOCTL_SECTORS * 512) {		retval = -EINVAL;		goto out;	}	/* Hardware can only do multiple of 512 byte transfers */	data_buffer_length_adjusted = (data_buffer_length + 511) & ~511;		/* Now allocate ioctl buf memory */	cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle, GFP_KERNEL);	if (cpu_addr == NULL) {		retval = -ENOMEM;		goto out;	}	tw_ioctl = (TW_New_Ioctl *)cpu_addr;	/* Now copy down the entire ioctl */	if (copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1))		goto out2;	passthru = (TW_Passthru *)&tw_ioctl->firmware_command;	/* See which ioctl we are doing */	switch (cmd) {		case TW_OP_NOP:			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");			break;		case TW_OP_AEN_LISTEN:			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");			memset(tw_ioctl->data_buffer, 0, data_buffer_length);			spin_lock_irqsave(tw_dev->host->host_lock, flags);			if (tw_dev->aen_head == tw_dev->aen_tail) {				tw_aen_code = TW_AEN_QUEUE_EMPTY;			} else {				tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];				if (tw_dev->aen_head == TW_Q_LENGTH - 1) {					tw_dev->aen_head = TW_Q_START;				} else {					tw_dev->aen_head = tw_dev->aen_head + 1;				}			}			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);			memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));			break;		case TW_CMD_PACKET_WITH_DATA:			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");			spin_lock_irqsave(tw_dev->host->host_lock, flags);			tw_state_request_start(tw_dev, &request_id);			/* Flag internal command */			tw_dev->srb[request_id] = NULL;			/* Flag chrdev ioctl */			tw_dev->chrdev_request_id = request_id;			tw_ioctl->firmware_command.request_id = request_id;			/* Load the sg list */			switch (TW_SGL_OUT(tw_ioctl->firmware_command.opcode__sgloffset)) {			case 2:				tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;				tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;				break;			case 3:				tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;				tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;				break;			case 5:				passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;				passthru->sg_list[0].length = data_buffer_length_adjusted;				break;			}			memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));			/* Now post the command packet to the controller */			tw_post_command_packet(tw_dev, request_id);			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);			timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;			/* Now wait for the command to complete */			timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);			/* We timed out, and didn't get an interrupt */			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {				/* Now we need to reset the board */				printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);				retval = -EIO;				if (tw_reset_device_extension(tw_dev)) {					printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);				}				goto out2;			}			/* Now copy in the command packet response */			memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));			/* Now complete the io */			spin_lock_irqsave(tw_dev->host->host_lock, flags);			tw_dev->posted_request_count--;			tw_dev->state[request_id] = TW_S_COMPLETED;			tw_state_request_finish(tw_dev, request_id);			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);			break;		default:			retval = -ENOTTY;			goto out2;	}	/* Now copy the response to userspace */	if (copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1))		goto out2;	retval = 0;out2:	/* Now free ioctl buf memory */	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);out:	mutex_unlock(&tw_dev->ioctl_lock);	return retval;} /* End tw_chrdev_ioctl() *//* This function handles open for the character device */static int tw_chrdev_open(struct inode *inode, struct file *file){	unsigned int minor_number;	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");	minor_number = iminor(inode);	if (minor_number >= tw_device_extension_count)		return -ENODEV;	return 0;} /* End tw_chrdev_open() *//* File operations struct for character device */static const struct file_operations tw_fops = {	.owner		= THIS_MODULE,	.ioctl		= tw_chrdev_ioctl,	.open		= tw_chrdev_open,	.release	= NULL};/* This function will free up device extension resources */static void tw_free_device_extension(TW_Device_Extension *tw_dev){	dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");	/* Free command packet and generic buffer memory */	if (tw_dev->command_packet_virtual_address[0])		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);	if (tw_dev->alignment_virtual_address[0])		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);} /* End tw_free_device_extension() *//* This function will send an initconnection command to controller */static int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) {	unsigned long command_que_value;	TW_Command  *command_packet;	TW_Response_Queue response_queue;	int request_id = 0;	dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");	/* Initialize InitConnection command packet */	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n");		return 1;	}	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];	memset(command_packet, 0, sizeof(TW_Sector));	command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_INIT_CONNECTION);	command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;	command_packet->request_id = request_id;	command_packet->status = 0x0;	command_packet->flags = 0x0;	command_packet->byte6.message_credits = message_credits; 	command_packet->byte8.init_connection.response_queue_pointer = 0x0;	command_que_value = tw_dev->command_packet_physical_address[request_id];	if (command_que_value == 0) {		printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n");		return 1;	}  	/* Send command packet to the board */	outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));    	/* Poll for completion */

⌨️ 快捷键说明

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