3w-9xxx.c

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

C
1,986
字号
				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_LOCK:		tw_lock = (TW_Lock *)tw_ioctl->data_buffer;		do_gettimeofday(&current_time);		current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);		if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {			tw_dev->ioctl_sem_lock = 1;			tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;			tw_ioctl->driver_command.status = 0;			tw_lock->time_remaining_msec = tw_lock->timeout_msec;		} else {			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;			tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;		}		break;	case TW_IOCTL_RELEASE_LOCK:		if (tw_dev->ioctl_sem_lock == 1) {			tw_dev->ioctl_sem_lock = 0;			tw_ioctl->driver_command.status = 0;		} else {			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;		}		break;	default:		retval = TW_IOCTL_ERROR_OS_ENOTTY;		goto out3;	}	/* Now copy the entire response to userspace */	if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)		retval = 0;out3:	/* Now free ioctl buf memory */	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);out2:	up(&tw_dev->ioctl_sem);out:	return retval;} /* End twa_chrdev_ioctl() *//* This function handles open for the character device */static int twa_chrdev_open(struct inode *inode, struct file *file){	unsigned int minor_number;	int retval = TW_IOCTL_ERROR_OS_ENODEV;	minor_number = iminor(inode);	if (minor_number >= twa_device_extension_count)		goto out;	retval = 0;out:	return retval;} /* End twa_chrdev_open() *//* This function will print readable messages from status register errors */static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value){	int retval = 1;	/* Check for various error conditions and handle them appropriately */	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");		writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));	}	if (status_reg_value & TW_STATUS_PCI_ABORT) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");		writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);	}	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));	}	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");		writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));	}	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {		if (tw_dev->reset_print == 0) {			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");			tw_dev->reset_print = 1;		}		goto out;	}	retval = 0;out:	return retval;} /* End twa_decode_bits() *//* This function will empty the response queue */static int twa_empty_response_queue(TW_Device_Extension *tw_dev){	u32 status_reg_value, response_que_value;	int count = 0, retval = 1;	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));	while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {		response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));		count++;	}	if (count == TW_MAX_RESPONSE_DRAIN)		goto out;	retval = 0;out:	return retval;} /* End twa_empty_response_queue() *//* This function passes sense keys from firmware to scsi layer */static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host){	TW_Command_Full *full_command_packet;	unsigned short error;	int retval = 1;	full_command_packet = tw_dev->command_packet_virt[request_id];	/* Don't print error for Logical unit not supported during rollcall */	error = full_command_packet->header.status_block.error;	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {		if (print_host)			printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",			       tw_dev->host->host_no,			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,			       full_command_packet->header.status_block.error,			       twa_string_lookup(twa_error_table,						 full_command_packet->header.status_block.error),			       full_command_packet->header.err_specific_desc);		else			printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,			       full_command_packet->header.status_block.error,			       twa_string_lookup(twa_error_table,						 full_command_packet->header.status_block.error),			       full_command_packet->header.err_specific_desc);	}	if (copy_sense) {		memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);		tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);		retval = TW_ISR_DONT_RESULT;		goto out;	}	retval = 0;out:	return retval;} /* End twa_fill_sense() *//* This function will free up device extension resources */static void twa_free_device_extension(TW_Device_Extension *tw_dev){	if (tw_dev->command_packet_virt[0])		pci_free_consistent(tw_dev->tw_pci_dev,				    sizeof(TW_Command_Full)*TW_Q_LENGTH,				    tw_dev->command_packet_virt[0],				    tw_dev->command_packet_phys[0]);	if (tw_dev->generic_buffer_virt[0])		pci_free_consistent(tw_dev->tw_pci_dev,				    TW_SECTOR_SIZE*TW_Q_LENGTH,				    tw_dev->generic_buffer_virt[0],				    tw_dev->generic_buffer_phys[0]);	if (tw_dev->event_queue[0])		kfree(tw_dev->event_queue[0]);} /* End twa_free_device_extension() *//* This function will free a request id */static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id){	tw_dev->free_queue[tw_dev->free_tail] = request_id;	tw_dev->state[request_id] = TW_S_FINISHED;	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;} /* End twa_free_request_id() *//* This function will get parameter table entires from the firmware */static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes){	TW_Command_Full *full_command_packet;	TW_Command *command_packet;	TW_Param_Apache *param;	unsigned long param_value;	void *retval = NULL;	/* Setup 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_GET_PARAM);	command_packet->size              = TW_COMMAND_SIZE;	command_packet->request_id        = request_id;	command_packet->byte6_offset.block_count = 1;	/* Now setup the param */	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];	memset(param, 0, TW_SECTOR_SIZE);	param->table_id = table_id | 0x8000;	param->parameter_id = parameter_id;	param->parameter_size_bytes = parameter_size_bytes;	param_value = tw_dev->generic_buffer_phys[request_id];	command_packet->byte8_offset.param.sgl[0].address = param_value;	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;	/* Post the command packet to the board */	twa_post_command_packet(tw_dev, request_id, 1);	/* Poll for completion */	if (twa_poll_response(tw_dev, request_id, 30))		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")	else		retval = (void *)&(param->data[0]);	tw_dev->posted_request_count--;	tw_dev->state[request_id] = TW_S_INITIAL;	return retval;} /* End twa_get_param() *//* This function will assign an available request id */static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id){	*request_id = tw_dev->free_queue[tw_dev->free_head];	tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;	tw_dev->state[*request_id] = TW_S_STARTED;} /* End twa_get_request_id() *//* This function will send an initconnection command to controller */static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, 			      u32 set_features, unsigned short current_fw_srl, 			      unsigned short current_fw_arch_id, 			      unsigned short current_fw_branch, 			      unsigned short current_fw_build, 			      unsigned short *fw_on_ctlr_srl, 			      unsigned short *fw_on_ctlr_arch_id, 			      unsigned short *fw_on_ctlr_branch, 			      unsigned short *fw_on_ctlr_build, 			      u32 *init_connect_result){	TW_Command_Full *full_command_packet;	TW_Initconnect *tw_initconnect;	int request_id = 0, retval = 1;	/* Initialize InitConnection command packet */	full_command_packet = tw_dev->command_packet_virt[request_id];	memset(full_command_packet, 0, sizeof(TW_Command_Full));	full_command_packet->header.header_desc.size_header = 128;		tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;	tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);	tw_initconnect->request_id = request_id;	tw_initconnect->message_credits = message_credits;	tw_initconnect->features = set_features;#if BITS_PER_LONG > 32	/* Turn on 64-bit sgl support */	tw_initconnect->features |= 1;#endif	if (set_features & TW_EXTENDED_INIT_CONNECT) {		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;		tw_initconnect->fw_srl = current_fw_srl;		tw_initconnect->fw_arch_id = current_fw_arch_id;		tw_initconnect->fw_branch = current_fw_branch;		tw_initconnect->fw_build = current_fw_build;	} else 		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;	/* Send command packet to the board */	twa_post_command_packet(tw_dev, request_id, 1);	/* Poll for completion */	if (twa_poll_response(tw_dev, request_id, 30)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");	} else {		if (set_features & TW_EXTENDED_INIT_CONNECT) {			*fw_on_ctlr_srl = tw_initconnect->fw_srl;			*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;			*fw_on_ctlr_branch = tw_initconnect->fw_branch;			*fw_on_ctlr_build = tw_initconnect->fw_build;			*init_connect_result = tw_initconnect->result;		}		retval = 0;	}	tw_dev->posted_request_count--;	tw_dev->state[request_id] = TW_S_INITIAL;	return retval;} /* End twa_initconnection() *//* This function will initialize the fields of a device extension */static int twa_initialize_device_extension(TW_Device_Extension *tw_dev){	int i, retval = 1;	/* Initialize command packet buffers */	if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");		goto out;	}	/* Initialize generic buffer */	if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");		goto out;	}	/* Allocate event info space */	tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);	if (!tw_dev->event_queue[0]) {		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");		goto out;	}	memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);	for (i = 0; i < TW_Q_LENGTH; i++) {		tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));		tw_dev->free_queue[i] = i;		tw_dev->state[i] = TW_S_INITIAL;	}	tw_dev->pending_head = TW_Q_START;	tw_dev->pending_tail = TW_Q_START;	tw_dev->free_head = TW_Q_START;	tw_dev->free_tail = TW_Q_START;	tw_dev->error_sequence_id = 1;	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;	init_MUTEX(&tw_dev->ioctl_sem);	init_waitqueue_head(&tw_dev->ioctl_wqueue);	retval = 0;out:	return retval;} /* End twa_initialize_device_extension() *//* This function is the interrupt service routine */static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	int request_id, error = 0;	u32 status_reg_value;	TW_Response_Queue response_que;	TW_Command_Full *full_command_packet;	TW_Command *command_packet;	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;	int handled = 0;	/* Get the per adapter lock */	spin_lock(tw_dev->host->host_lock);	/* See if the interrupt matches this instance */	if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {		handled = 1;		/* Read the registers */		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));		/* Check if this is our interrupt, otherwise bail */		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))			goto twa_interrupt_bail;		/* Check controller for errors */		if (twa_check_bits(status_reg_value)) {			if (twa_decode_bits(tw_dev, status_reg_value)) {				TW_CLEAR_ALL_INTERRUPTS(tw_dev);				goto twa_interrupt_bail;			}		}

⌨️ 快捷键说明

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