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

📄 3w-xxxx.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
/*    3w-xxxx.c -- 3ware Storage Controller device driver for Linux.   Written By: Adam Radford <linux@3ware.com>   Modifications By: Joel Jacobson <linux@3ware.com>   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>   Copyright (C) 1999-2000 3ware Inc.   Kernel compatablity By: 	Andre Hedrick <andre@suse.com>   Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>      Further tiny build fixes and trivial hoovering    Alan Cox   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; version 2 of the License.   This program is distributed in the hope that it will be useful,              but WITHOUT ANY WARRANTY; without even the implied warranty of               MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                GNU General Public License for more details.                                 NO WARRANTY                                                                  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR           CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT         LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,         MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is       solely responsible for determining the appropriateness of using and          distributing the Program and assumes all risks associated with its           exercise of rights under this Agreement, including but not limited to        the risks and costs of program errors, damage to or loss of data,            programs or equipment, and unavailability or interruption of operations.     DISCLAIMER OF LIABILITY                                                      NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY      DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL           DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND      ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR        TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE       USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED     HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES                You should have received a copy of the GNU General Public License            along with this program; if not, write to the Free Software                  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    Bugs/Comments/Suggestions should be mailed to:                               linux@3ware.com   For more information, goto:   http://www.3ware.com   History   -------   0.1.000 -     Initial release.   0.4.000 -     Added support for Asynchronous Event Notification through                 ioctls for 3DM.   1.0.000 -     Added DPO & FUA bit support for WRITE_10 & WRITE_6 cdb                 to disable drive write-cache before writes.   1.1.000 -     Fixed performance bug with DPO & FUA not existing for WRITE_6.   1.2.000 -     Added support for clean shutdown notification/feature table.   1.02.00.001 - Added support for full command packet posts through ioctls                 for 3DM.                 Bug fix so hot spare drives don't show up.   1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some                 systems.   08/21/00    - release previously allocated resources on failure at                 tw_allocate_memory (acme)*/#include <linux/module.h>MODULE_AUTHOR ("3ware Inc.");MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");#include <linux/kernel.h>#include <linux/pci.h>#include <linux/time.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/blk.h>#include <linux/hdreg.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/smp.h>#include <linux/reboot.h>#include <linux/spinlock.h>#include <asm/errno.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#define __3W_C			/* let 3w-xxxx.h know it is use */#include "sd.h"#include "scsi.h"#include "hosts.h"#include "3w-xxxx.h"static int tw_copy_info(TW_Info *info, char *fmt, ...);static void tw_copy_mem_info(TW_Info *info, char *data, int len);static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int tw_halt(struct notifier_block *nb, ulong event, void *buf);/* Notifier block to get a notify on system shutdown/halt/reboot */static struct notifier_block tw_notifier = {  tw_halt, NULL, 0};/* Globals */char *tw_driver_version="1.02.00.002";TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];int tw_device_extension_count = 0;/* Functions *//* This function will complete an aen request from the isr */int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) {	TW_Param *param;	unsigned short aen, aen_code;	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);	aen_code = (aen & 0x0ff);	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen_code);	/* Now queue the code */	tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;	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;		}	}	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 */int tw_aen_drain_queue(TW_Device_Extension *tw_dev){	TW_Command *command_packet;	TW_Param *param;	int tries = 0;	int request_id = 0;	u32 command_que_value = 0, command_que_addr;	u32 status_reg_value = 0, status_reg_addr;	u32 param_value;	TW_Response_Queue response_queue;	u32 response_que_addr;	unsigned short aen;	unsigned short aen_code;	int finished = 0;	int first_reset = 0;	int queue = 0;	int imax, i;	int found = 0;	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");	command_que_addr = tw_dev->registers.command_que_addr;	status_reg_addr = tw_dev->registers.status_reg_addr;	response_que_addr = tw_dev->registers.response_que_addr;	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d\n", tw_dev->host->host_no);		return 1;	}	/* 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->byte0.opcode = TW_OP_GET_PARAM;	command_packet->byte0.sgl_offset = 2;	command_packet->size = 4;	command_packet->request_id = request_id;	command_packet->byte3.unit = 0;	command_packet->byte3.host_id = 0;	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) {		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);	imax = TW_POLL_MAX_RETRIES;	/* Now drain the controller's aen queue */	do {		/* Post command packet */		outl(command_que_value, command_que_addr);    		/* Now poll for completion */		for (i=0;i<imax;i++) {			mdelay(10);			status_reg_value = inl(status_reg_addr);			if (tw_check_bits(status_reg_value)) {				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");				return 1;			}			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {				response_queue.value = inl(response_que_addr);				request_id = (unsigned char)response_queue.u.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 */						printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);						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_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");						if (first_reset != 1) {							continue;						} else {							finished = 1;						}						break;					case TW_AEN_SOFT_RESET:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");						if (first_reset == 0) {							first_reset = 1;						} else {							queue = 1;						}						break;					case TW_AEN_DEGRADED_MIRROR:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");						queue = 1;						break;					case TW_AEN_CONTROLLER_ERROR:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");						queue = 1;						break;					case TW_AEN_REBUILD_FAIL:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");						queue = 1;						break;					case TW_AEN_REBUILD_DONE:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");						queue = 1;						break;					case TW_AEN_QUEUE_FULL:						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");						queue = 1;						break;					default:						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);						queue = 1;				}				/* Now put the aen on the aen_queue */				if (queue == 1) {					tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;					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;				break;			}		}		if (found == 0) {			printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");			return 1;		}		tries++;	} while ((tries < TW_MAX_AEN_TRIES) && (finished == 0));	if (tries >=TW_MAX_AEN_TRIES) {		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Aen queue error.\n");		return 1;	}	return 0;} /* End tw_aen_drain_queue() *//* This function will read the aen queue from the isr */int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) {	TW_Command *command_packet;	TW_Param *param;	u32 command_que_value = 0, command_que_addr;	u32 status_reg_value = 0, status_reg_addr;	u32 param_value = 0;	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");	command_que_addr = tw_dev->registers.command_que_addr;	status_reg_addr = tw_dev->registers.status_reg_addr;	status_reg_value = inl(status_reg_addr);	if (tw_check_bits(status_reg_value)) {		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");		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->byte0.opcode = TW_OP_GET_PARAM;	command_packet->byte0.sgl_offset = 2;	command_packet->size = 4;	command_packet->request_id = request_id;	command_packet->byte3.unit = 0;	command_packet->byte3.host_id = 0;	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;

⌨️ 快捷键说明

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