3w-9xxx.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,986 行 · 第 1/5 页

C
1,986
字号
		tw_dev->aen_count--;	if ((tw_dev->error_index + 1) == TW_Q_LENGTH)		tw_dev->event_queue_wrapped = 1;	tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;} /* End twa_aen_queue_event() *//* This function will read the aen queue from the isr */static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id){	char cdb[TW_MAX_CDB_LEN];	TW_SG_Apache sglist[1];	TW_Command_Full *full_command_packet;	int retval = 1;	full_command_packet = tw_dev->command_packet_virt[request_id];	memset(full_command_packet, 0, sizeof(TW_Command_Full));	/* Initialize cdb */	memset(&cdb, 0, TW_MAX_CDB_LEN);	cdb[0] = REQUEST_SENSE; /* opcode */	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */	/* Initialize sglist */	memset(&sglist, 0, sizeof(TW_SG_Apache));	sglist[0].length = TW_SECTOR_SIZE;	sglist[0].address = tw_dev->generic_buffer_phys[request_id];	/* Mark internal command */	tw_dev->srb[request_id] = NULL;	/* Now post the command packet */	if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");		goto out;	}	retval = 0;out:	return retval;} /* End twa_aen_read_queue() *//* This function will look up an AEN severity string */static char *twa_aen_severity_lookup(unsigned char severity_code){	char *retval = NULL;	if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||	    (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))		goto out;	retval = twa_aen_severity_table[severity_code];out:	return retval;} /* End twa_aen_severity_lookup() *//* This function will sync firmware time with the host time */static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id){	u32 schedulertime;	struct timeval utc;	TW_Command_Full *full_command_packet;	TW_Command *command_packet;	TW_Param_Apache *param;	u32 local_time;	/* Fill out the command packet */	full_command_packet = tw_dev->command_packet_virt[request_id];	memset(full_command_packet, 0, sizeof(TW_Command_Full));	command_packet = &full_command_packet->command.oldcommand;	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);	command_packet->request_id = request_id;	command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id];	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;	command_packet->size = TW_COMMAND_SIZE;	command_packet->byte6_offset.parameter_count = 1;	/* Setup the param */	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];	memset(param, 0, TW_SECTOR_SIZE);	param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */	param->parameter_id = 0x3; /* SchedulerTime */	param->parameter_size_bytes = 4;	/* Convert system time in UTC to local time seconds since last            Sunday 12:00AM */	do_gettimeofday(&utc);	local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));	schedulertime = local_time - (3 * 86400);	schedulertime = schedulertime % 604800;	memcpy(param->data, &schedulertime, sizeof(u32));	/* Mark internal command */	tw_dev->srb[request_id] = NULL;	/* Now post the command */	twa_post_command_packet(tw_dev, request_id, 1);} /* End twa_aen_sync_time() *//* This function will allocate memory and check if it is correctly aligned */static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which){	int i;	dma_addr_t dma_handle;	unsigned long *cpu_addr;	int retval = 1;	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);	if (!cpu_addr) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");		goto out;	}	if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);		goto out;	}	memset(cpu_addr, 0, size*TW_Q_LENGTH);	for (i = 0; i < TW_Q_LENGTH; i++) {		switch(which) {		case 0:			tw_dev->command_packet_phys[i] = dma_handle+(i*size);			tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));			break;		case 1:			tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);			tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));			break;		}	}	retval = 0;out:	return retval;} /* End twa_allocate_memory() *//* This function will check the status register for unexpected bits */static int twa_check_bits(u32 status_reg_value){	int retval = 1;	if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)		goto out;	if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)		goto out;	retval = 0;out:	return retval;} /* End twa_check_bits() *//* This function will check the srl and decide if we are compatible  */static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed){	int retval = 1;	unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;	unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;	u32 init_connect_result = 0;	if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,			       TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL,			       TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH,			       TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl,			       &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,			       &fw_on_ctlr_build, &init_connect_result)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");		goto out;	}	tw_dev->working_srl = TW_CURRENT_FW_SRL;	tw_dev->working_branch = TW_CURRENT_FW_BRANCH;	tw_dev->working_build = TW_CURRENT_FW_BUILD;	/* Try base mode compatibility */	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {		if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,				       TW_EXTENDED_INIT_CONNECT,				       TW_BASE_FW_SRL, TW_9000_ARCH_ID,				       TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,				       &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,				       &fw_on_ctlr_branch, &fw_on_ctlr_build,				       &init_connect_result)) {			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");			goto out;		}		if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {			if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");			} else {				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");			}			goto out;		}		tw_dev->working_srl = TW_BASE_FW_SRL;		tw_dev->working_branch = TW_BASE_FW_BRANCH;		tw_dev->working_build = TW_BASE_FW_BUILD;	}	retval = 0;out:	return retval;} /* End twa_check_srl() *//* This function handles ioctl for the character device */static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	long timeout;	unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;	dma_addr_t dma_handle;	int request_id = 0;	unsigned int sequence_id = 0;	unsigned char event_index, start_index;	TW_Ioctl_Driver_Command driver_command;	TW_Ioctl_Buf_Apache *tw_ioctl;	TW_Lock *tw_lock;	TW_Command_Full *full_command_packet;	TW_Compatibility_Info *tw_compat_info;	TW_Event *event;	struct timeval current_time;	u32 current_time_ms;	TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];	int retval = TW_IOCTL_ERROR_OS_EFAULT;	void __user *argp = (void __user *)arg;	/* Only let one of these through at a time */	if (down_interruptible(&tw_dev->ioctl_sem)) {		retval = TW_IOCTL_ERROR_OS_EINTR;		goto out;	}	/* First copy down the driver command */	if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))		goto out2;	/* Check data buffer size */	if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {		retval = TW_IOCTL_ERROR_OS_EINVAL;		goto out2;	}	/* Hardware can only do multiple of 512 byte transfers */	data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;	/* Now allocate ioctl buf memory */	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);	if (!cpu_addr) {		retval = TW_IOCTL_ERROR_OS_ENOMEM;		goto out2;	}	tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;	/* Now copy down the entire ioctl */	if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))		goto out3;	/* See which ioctl we are doing */	switch (cmd) {	case TW_IOCTL_FIRMWARE_PASS_THROUGH:		spin_lock_irqsave(tw_dev->host->host_lock, flags);		twa_get_request_id(tw_dev, &request_id);		/* Flag internal command */		tw_dev->srb[request_id] = NULL;		/* Flag chrdev ioctl */		tw_dev->chrdev_request_id = request_id;		full_command_packet = &tw_ioctl->firmware_command;		/* Load request id and sglist for both command types */		twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);		memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));		/* Now post the command packet to the controller */		twa_post_command_packet(tw_dev, request_id, 1);		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);		timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;		/* Now wait for command to complete */		timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);		/* Check if we timed out, got a signal, or didn't get                   an interrupt */		if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {			/* Now we need to reset the board */			if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {				retval = timeout;			} else {				printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",				       tw_dev->host->host_no, TW_DRIVER, 0xc,				       cmd);				retval = TW_IOCTL_ERROR_OS_EIO;			}			spin_lock_irqsave(tw_dev->host->host_lock, flags);			tw_dev->state[request_id] = TW_S_COMPLETED;			twa_free_request_id(tw_dev, request_id);			tw_dev->posted_request_count--;			twa_reset_device_extension(tw_dev);			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);			goto out3;		}		/* Now copy in the command packet response */		memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));				/* 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;		twa_free_request_id(tw_dev, request_id);		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);		break;	case TW_IOCTL_GET_COMPATIBILITY_INFO:		tw_ioctl->driver_command.status = 0;		/* Copy compatiblity struct into ioctl data buffer */		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;		strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));		tw_compat_info->working_srl = tw_dev->working_srl;		tw_compat_info->working_branch = tw_dev->working_branch;		tw_compat_info->working_build = tw_dev->working_build;		break;	case TW_IOCTL_GET_LAST_EVENT:		if (tw_dev->event_queue_wrapped) {			if (tw_dev->aen_clobber) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;				tw_dev->aen_clobber = 0;			} else				tw_ioctl->driver_command.status = 0;		} else {			if (!tw_dev->error_index) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;				break;			}			tw_ioctl->driver_command.status = 0;		}		event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;		break;	case TW_IOCTL_GET_FIRST_EVENT:		if (tw_dev->event_queue_wrapped) {			if (tw_dev->aen_clobber) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;				tw_dev->aen_clobber = 0;			} else 				tw_ioctl->driver_command.status = 0;			event_index = tw_dev->error_index;		} else {			if (!tw_dev->error_index) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;				break;			}			tw_ioctl->driver_command.status = 0;			event_index = 0;		}		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;		break;	case TW_IOCTL_GET_NEXT_EVENT:		event = (TW_Event *)tw_ioctl->data_buffer;		sequence_id = event->sequence_id;		tw_ioctl->driver_command.status = 0;		if (tw_dev->event_queue_wrapped) {			if (tw_dev->aen_clobber) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;				tw_dev->aen_clobber = 0;			}			start_index = tw_dev->error_index;		} else {			if (!tw_dev->error_index) {				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;				break;			}			start_index = 0;		}		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;		if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)				tw_dev->aen_clobber = 1;			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;			break;		}		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;		break;	case TW_IOCTL_GET_PREVIOUS_EVENT:		event = (TW_Event *)tw_ioctl->data_buffer;		sequence_id = event->sequence_id;		tw_ioctl->driver_command.status = 0;		if (tw_dev->event_queue_wrapped) {			if (tw_dev->aen_clobber) {

⌨️ 快捷键说明

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