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

📄 3w-xxxx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {		/* We successfully posted the command packet */		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));		tw_dev->state[request_id] = TW_S_POSTED;		tw_dev->posted_request_count++;		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {			tw_dev->max_posted_request_count = tw_dev->posted_request_count;		}	} else {		/* Couldn't post the command packet, so we do it in the isr */		if (tw_dev->state[request_id] != TW_S_PENDING) {			tw_dev->state[request_id] = TW_S_PENDING;			tw_dev->pending_request_count++;			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {				tw_dev->max_pending_request_count = tw_dev->pending_request_count;			}			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;			if (tw_dev->pending_tail == TW_Q_LENGTH-1) {				tw_dev->pending_tail = TW_Q_START;			} else {				tw_dev->pending_tail = tw_dev->pending_tail + 1;			}		} 		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);		return 1;	}	return 0;} /* End tw_post_command_packet() *//* This function will return valid sense buffer information for failed cmds */static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense){	int i;	TW_Command *command;        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, TW_UNIT_OUT(command->unit__hostid));	/* Attempt to return intelligent sense information */	if (fill_sense) {		if ((command->status == 0xc7) || (command->status == 0xcb)) {			for (i = 0; i < ARRAY_SIZE(tw_sense_table); i++) {				if (command->flags == tw_sense_table[i][0]) {					/* Valid bit and 'current errors' */					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);					/* Sense key */					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];					/* Additional sense length */					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */					/* Additional sense code */					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];					/* Additional sense code qualifier */					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);					return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */				}			}		}		/* If no table match, error so we get a reset */		return 1;	}	return 0;} /* End tw_decode_sense() *//* This function will report controller error status */static int tw_check_errors(TW_Device_Extension *tw_dev) {	u32 status_reg_value;  	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {		tw_decode_bits(tw_dev, status_reg_value, 0);		return 1;	}	return 0;} /* End tw_check_errors() *//* This function will empty the response que */static void tw_empty_response_que(TW_Device_Extension *tw_dev) {	u32 status_reg_value, response_que_value;	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));	while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {		response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));		status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));	}} /* End tw_empty_response_que() *//* This function will free a request_id */static void tw_state_request_finish(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 tw_state_request_finish() *//* This function will assign an available request_id */static void tw_state_request_start(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 tw_state_request_start() *//* Show some statistics about the card */static ssize_t tw_show_stats(struct class_device *class_dev, char *buf){	struct Scsi_Host *host = class_to_shost(class_dev);	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;	unsigned long flags = 0;	ssize_t len;	spin_lock_irqsave(tw_dev->host->host_lock, flags);	len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n"		       "Current commands posted:   %4d\n"		       "Max commands posted:       %4d\n"		       "Current pending commands:  %4d\n"		       "Max pending commands:      %4d\n"		       "Last sgl length:           %4d\n"		       "Max sgl length:            %4d\n"		       "Last sector count:         %4d\n"		       "Max sector count:          %4d\n"		       "SCSI Host Resets:          %4d\n"		       "AEN's:                     %4d\n", 		       TW_DRIVER_VERSION,		       tw_dev->posted_request_count,		       tw_dev->max_posted_request_count,		       tw_dev->pending_request_count,		       tw_dev->max_pending_request_count,		       tw_dev->sgl_entries,		       tw_dev->max_sgl_entries,		       tw_dev->sector_count,		       tw_dev->max_sector_count,		       tw_dev->num_resets,		       tw_dev->aen_count);	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);	return len;} /* End tw_show_stats() *//* This function will set a devices queue depth */static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth){	if (queue_depth > TW_Q_LENGTH-2)		queue_depth = TW_Q_LENGTH-2;	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);	return queue_depth;} /* End tw_change_queue_depth() *//* Create sysfs 'stats' entry */static struct class_device_attribute tw_host_stats_attr = {	.attr = {		.name = 	"stats",		.mode =		S_IRUGO,	},	.show = tw_show_stats};/* Host attributes initializer */static struct class_device_attribute *tw_host_attrs[] = {	&tw_host_stats_attr,	NULL,};/* This function will read the aen queue from the isr */static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) {	TW_Command *command_packet;	TW_Param *param;	unsigned long command_que_value;	u32 status_reg_value;	unsigned long param_value = 0;	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));	if (tw_check_bits(status_reg_value)) {		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");		tw_decode_bits(tw_dev, status_reg_value, 1);		return 1;	}	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): 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(2, TW_OP_GET_PARAM);	command_packet->size = 4;	command_packet->request_id = request_id;	command_packet->status = 0;	command_packet->flags = 0;	command_packet->byte6.parameter_count = 1;	command_que_value = tw_dev->command_packet_physical_address[request_id];	if (command_que_value == 0) {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet physical address.\n");		return 1;	}	/* Now setup the param */	if (tw_dev->alignment_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment virtual address.\n");		return 1;	}	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];	memset(param, 0, sizeof(TW_Sector));	param->table_id = 0x401; /* AEN table */	param->parameter_id = 2; /* Unit code */	param->parameter_size_bytes = 2;	param_value = tw_dev->alignment_physical_address[request_id];	if (param_value == 0) {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_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 post the command packet */	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n");		tw_dev->srb[request_id] = NULL; /* Flag internal command */		tw_dev->state[request_id] = TW_S_POSTED;		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));	} else {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n");		return 1;	}	return 0;} /* End tw_aen_read_queue() *//* This function will complete an aen request from the isr */static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) {	TW_Param *param;	unsigned short aen;	int error = 0, table_max = 0;	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");	if (tw_dev->alignment_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");		return 1;	}	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];	aen = *(unsigned short *)(param->data);	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);	/* Print some useful info when certain aen codes come out */	if (aen == 0x0ff) {		printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);	} 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: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);			} else {				if (aen != 0x0) 					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);			}		} else {			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);		}	}	if (aen != TW_AEN_QUEUE_EMPTY) {		tw_dev->aen_count++;		/* Now queue the code */		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;			}		}		error = tw_aen_read_queue(tw_dev, request_id);		if (error) {			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);			tw_dev->state[request_id] = TW_S_COMPLETED;			tw_state_request_finish(tw_dev, request_id);		}	} else {		tw_dev->state[request_id] = TW_S_COMPLETED;		tw_state_request_finish(tw_dev, request_id);	}	return 0;} /* End tw_aen_complete() *//* This function will drain the aen queue after a soft reset */static int tw_aen_drain_queue(TW_Device_Extension *tw_dev){	TW_Command *command_packet;	TW_Param *param;	int request_id = 0;	unsigned long command_que_value;	unsigned long param_value;	TW_Response_Queue response_queue;	unsigned short aen;	unsigned short aen_code;	int finished = 0;	int first_reset = 0;	int queue = 0;	int found = 0, table_max = 0;	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);		return 1;	}	TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);	/* Empty response queue */	tw_empty_response_que(tw_dev);	/* Initialize command packet */	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): 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(2, TW_OP_GET_PARAM);	command_packet->size = 4;	command_packet->request_id = request_id;	command_packet->status = 0;	command_packet->flags = 0;	command_packet->byte6.parameter_count = 1;	command_que_value = tw_dev->command_packet_physical_address[request_id];	if (command_que_value == 0) {		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n");		return 1;	}	/* Now setup the param */	if (tw_dev->alignment_virtual_address[request_id] == NULL) {		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n");		return 1;	}	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];	memset(param, 0, sizeof(TW_Sector));	param->table_id = 0x401; /* AEN table */	param->parameter_id = 2; /* Unit code */	param->parameter_size_bytes = 2;	param_value = tw_dev->alignment_physical_address[request_id];	if (param_value == 0) {

⌨️ 快捷键说明

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