欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

stex.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
/* * SuperTrak EX Series Storage Controller driver for Linux * *	Copyright (C) 2005, 2006 Promise Technology Inc. * *	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; either version *	2 of the License, or (at your option) any later version. * *	Written By: *		Ed Lin <promise_linux@promise.com> * */#include <linux/init.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/time.h>#include <linux/pci.h>#include <linux/blkdev.h>#include <linux/interrupt.h>#include <linux/types.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <scsi/scsi.h>#include <scsi/scsi_device.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_dbg.h>#define DRV_NAME "stex"#define ST_DRIVER_VERSION "3.6.0000.1"#define ST_VER_MAJOR 		3#define ST_VER_MINOR 		6#define ST_OEM 			0#define ST_BUILD_VER 		1enum {	/* MU register offset */	IMR0	= 0x10,	/* MU_INBOUND_MESSAGE_REG0 */	IMR1	= 0x14,	/* MU_INBOUND_MESSAGE_REG1 */	OMR0	= 0x18,	/* MU_OUTBOUND_MESSAGE_REG0 */	OMR1	= 0x1c,	/* MU_OUTBOUND_MESSAGE_REG1 */	IDBL	= 0x20,	/* MU_INBOUND_DOORBELL */	IIS	= 0x24,	/* MU_INBOUND_INTERRUPT_STATUS */	IIM	= 0x28,	/* MU_INBOUND_INTERRUPT_MASK */	ODBL	= 0x2c,	/* MU_OUTBOUND_DOORBELL */	OIS	= 0x30,	/* MU_OUTBOUND_INTERRUPT_STATUS */	OIM	= 0x3c,	/* MU_OUTBOUND_INTERRUPT_MASK */	/* MU register value */	MU_INBOUND_DOORBELL_HANDSHAKE		= 1,	MU_INBOUND_DOORBELL_REQHEADCHANGED	= 2,	MU_INBOUND_DOORBELL_STATUSTAILCHANGED	= 4,	MU_INBOUND_DOORBELL_HMUSTOPPED		= 8,	MU_INBOUND_DOORBELL_RESET		= 16,	MU_OUTBOUND_DOORBELL_HANDSHAKE		= 1,	MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED	= 2,	MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED	= 4,	MU_OUTBOUND_DOORBELL_BUSCHANGE		= 8,	MU_OUTBOUND_DOORBELL_HASEVENT		= 16,	/* MU status code */	MU_STATE_STARTING			= 1,	MU_STATE_FMU_READY_FOR_HANDSHAKE	= 2,	MU_STATE_SEND_HANDSHAKE_FRAME		= 3,	MU_STATE_STARTED			= 4,	MU_STATE_RESETTING			= 5,	MU_MAX_DELAY				= 120,	MU_HANDSHAKE_SIGNATURE			= 0x55aaaa55,	MU_HANDSHAKE_SIGNATURE_HALF		= 0x5a5a0000,	MU_HARD_RESET_WAIT			= 30000,	HMU_PARTNER_TYPE			= 2,	/* firmware returned values */	SRB_STATUS_SUCCESS			= 0x01,	SRB_STATUS_ERROR			= 0x04,	SRB_STATUS_BUSY				= 0x05,	SRB_STATUS_INVALID_REQUEST		= 0x06,	SRB_STATUS_SELECTION_TIMEOUT		= 0x0A,	SRB_SEE_SENSE 				= 0x80,	/* task attribute */	TASK_ATTRIBUTE_SIMPLE			= 0x0,	TASK_ATTRIBUTE_HEADOFQUEUE		= 0x1,	TASK_ATTRIBUTE_ORDERED			= 0x2,	TASK_ATTRIBUTE_ACA			= 0x4,	/* request count, etc. */	MU_MAX_REQUEST				= 32,	/* one message wasted, use MU_MAX_REQUEST+1		to handle MU_MAX_REQUEST messages */	MU_REQ_COUNT				= (MU_MAX_REQUEST + 1),	MU_STATUS_COUNT				= (MU_MAX_REQUEST + 1),	STEX_CDB_LENGTH				= MAX_COMMAND_SIZE,	REQ_VARIABLE_LEN			= 1024,	STATUS_VAR_LEN				= 128,	ST_CAN_QUEUE				= MU_MAX_REQUEST,	ST_CMD_PER_LUN				= MU_MAX_REQUEST,	ST_MAX_SG				= 32,	/* sg flags */	SG_CF_EOT				= 0x80,	/* end of table */	SG_CF_64B				= 0x40,	/* 64 bit item */	SG_CF_HOST				= 0x20,	/* sg in host memory */	st_shasta				= 0,	st_vsc					= 1,	st_vsc1					= 2,	st_yosemite				= 3,	PASSTHRU_REQ_TYPE			= 0x00000001,	PASSTHRU_REQ_NO_WAKEUP			= 0x00000100,	ST_INTERNAL_TIMEOUT			= 30,	ST_TO_CMD				= 0,	ST_FROM_CMD				= 1,	/* vendor specific commands of Promise */	MGT_CMD					= 0xd8,	SINBAND_MGT_CMD				= 0xd9,	ARRAY_CMD				= 0xe0,	CONTROLLER_CMD				= 0xe1,	DEBUGGING_CMD				= 0xe2,	PASSTHRU_CMD				= 0xe3,	PASSTHRU_GET_ADAPTER			= 0x05,	PASSTHRU_GET_DRVVER			= 0x10,	CTLR_CONFIG_CMD				= 0x03,	CTLR_SHUTDOWN				= 0x0d,	CTLR_POWER_STATE_CHANGE			= 0x0e,	CTLR_POWER_SAVING			= 0x01,	PASSTHRU_SIGNATURE			= 0x4e415041,	MGT_CMD_SIGNATURE			= 0xba,	INQUIRY_EVPD				= 0x01,	ST_ADDITIONAL_MEM			= 0x200000,};/* SCSI inquiry data */typedef struct st_inq {	u8 DeviceType			:5;	u8 DeviceTypeQualifier		:3;	u8 DeviceTypeModifier		:7;	u8 RemovableMedia		:1;	u8 Versions;	u8 ResponseDataFormat		:4;	u8 HiSupport			:1;	u8 NormACA			:1;	u8 ReservedBit			:1;	u8 AERC				:1;	u8 AdditionalLength;	u8 Reserved[2];	u8 SoftReset			:1;	u8 CommandQueue			:1;	u8 Reserved2			:1;	u8 LinkedCommands		:1;	u8 Synchronous			:1;	u8 Wide16Bit			:1;	u8 Wide32Bit			:1;	u8 RelativeAddressing		:1;	u8 VendorId[8];	u8 ProductId[16];	u8 ProductRevisionLevel[4];	u8 VendorSpecific[20];	u8 Reserved3[40];} ST_INQ;struct st_sgitem {	u8 ctrl;	/* SG_CF_xxx */	u8 reserved[3];	__le32 count;	__le32 addr;	__le32 addr_hi;};struct st_sgtable {	__le16 sg_count;	__le16 max_sg_count;	__le32 sz_in_byte;	struct st_sgitem table[ST_MAX_SG];};struct handshake_frame {	__le32 rb_phy;		/* request payload queue physical address */	__le32 rb_phy_hi;	__le16 req_sz;		/* size of each request payload */	__le16 req_cnt;		/* count of reqs the buffer can hold */	__le16 status_sz;	/* size of each status payload */	__le16 status_cnt;	/* count of status the buffer can hold */	__le32 hosttime;	/* seconds from Jan 1, 1970 (GMT) */	__le32 hosttime_hi;	u8 partner_type;	/* who sends this frame */	u8 reserved0[7];	__le32 partner_ver_major;	__le32 partner_ver_minor;	__le32 partner_ver_oem;	__le32 partner_ver_build;	__le32 extra_offset;	/* NEW */	__le32 extra_size;	/* NEW */	u32 reserved1[2];};struct req_msg {	__le16 tag;	u8 lun;	u8 target;	u8 task_attr;	u8 task_manage;	u8 prd_entry;	u8 payload_sz;		/* payload size in 4-byte, not used */	u8 cdb[STEX_CDB_LENGTH];	u8 variable[REQ_VARIABLE_LEN];};struct status_msg {	__le16 tag;	u8 lun;	u8 target;	u8 srb_status;	u8 scsi_status;	u8 reserved;	u8 payload_sz;		/* payload size in 4-byte */	u8 variable[STATUS_VAR_LEN];};struct ver_info {	u32 major;	u32 minor;	u32 oem;	u32 build;	u32 reserved[2];};struct st_frame {	u32 base[6];	u32 rom_addr;	struct ver_info drv_ver;	struct ver_info bios_ver;	u32 bus;	u32 slot;	u32 irq_level;	u32 irq_vec;	u32 id;	u32 subid;	u32 dimm_size;	u8 dimm_type;	u8 reserved[3];	u32 channel;	u32 reserved1;};struct st_drvver {	u32 major;	u32 minor;	u32 oem;	u32 build;	u32 signature[2];	u8 console_id;	u8 host_no;	u8 reserved0[2];	u32 reserved[3];};#define MU_REQ_BUFFER_SIZE	(MU_REQ_COUNT * sizeof(struct req_msg))#define MU_STATUS_BUFFER_SIZE	(MU_STATUS_COUNT * sizeof(struct status_msg))#define MU_BUFFER_SIZE		(MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)#define STEX_EXTRA_SIZE		max(sizeof(struct st_frame), sizeof(ST_INQ))#define STEX_BUFFER_SIZE	(MU_BUFFER_SIZE + STEX_EXTRA_SIZE)struct st_ccb {	struct req_msg *req;	struct scsi_cmnd *cmd;	void *sense_buffer;	unsigned int sense_bufflen;	int sg_count;	u32 req_type;	u8 srb_status;	u8 scsi_status;};struct st_hba {	void __iomem *mmio_base;	/* iomapped PCI memory space */	void *dma_mem;	dma_addr_t dma_handle;	size_t dma_size;	struct Scsi_Host *host;	struct pci_dev *pdev;	u32 req_head;	u32 req_tail;	u32 status_head;	u32 status_tail;	struct status_msg *status_buffer;	void *copy_buffer; /* temp buffer for driver-handled commands */	struct st_ccb ccb[MU_MAX_REQUEST];	struct st_ccb *wait_ccb;	wait_queue_head_t waitq;	unsigned int mu_status;	int out_req_cnt;	unsigned int cardtype;};static const char console_inq_page[] ={	0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30,	0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20,	/* "Promise " */	0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E,	/* "RAID Con" */	0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20,	/* "sole    " */	0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20,	/* "1.00    " */	0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D,	/* "SX/RSAF-" */	0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20,	/* "TE1.00  " */	0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20};MODULE_AUTHOR("Ed Lin");MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");MODULE_LICENSE("GPL");MODULE_VERSION(ST_DRIVER_VERSION);static void stex_gettime(__le32 *time){	struct timeval tv;	do_gettimeofday(&tv);	*time = cpu_to_le32(tv.tv_sec & 0xffffffff);	*(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);}static struct status_msg *stex_get_status(struct st_hba *hba){	struct status_msg *status =		hba->status_buffer + hba->status_tail;	++hba->status_tail;	hba->status_tail %= MU_STATUS_COUNT;	return status;}static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq){	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;	cmd->sense_buffer[0] = 0x70;    /* fixed format, current */	cmd->sense_buffer[2] = sk;	cmd->sense_buffer[7] = 18 - 8;  /* additional sense length */	cmd->sense_buffer[12] = asc;	cmd->sense_buffer[13] = ascq;}static void stex_invalid_field(struct scsi_cmnd *cmd,			       void (*done)(struct scsi_cmnd *)){	/* "Invalid field in cbd" */	stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);	done(cmd);}static struct req_msg *stex_alloc_req(struct st_hba *hba){	struct req_msg *req = ((struct req_msg *)hba->dma_mem) +		hba->req_head;	++hba->req_head;	hba->req_head %= MU_REQ_COUNT;	return req;}static int stex_map_sg(struct st_hba *hba,	struct req_msg *req, struct st_ccb *ccb){	struct scsi_cmnd *cmd;	struct scatterlist *sg;	struct st_sgtable *dst;	int i, nseg;	cmd = ccb->cmd;	dst = (struct st_sgtable *)req->variable;	dst->max_sg_count = cpu_to_le16(ST_MAX_SG);	dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd));	nseg = scsi_dma_map(cmd);	if (nseg < 0)		return -EIO;	if (nseg) {		ccb->sg_count = nseg;		dst->sg_count = cpu_to_le16((u16)nseg);		scsi_for_each_sg(cmd, sg, nseg, i) {			dst->table[i].count = cpu_to_le32((u32)sg_dma_len(sg));			dst->table[i].addr =				cpu_to_le32(sg_dma_address(sg) & 0xffffffff);			dst->table[i].addr_hi =				cpu_to_le32((sg_dma_address(sg) >> 16) >> 16);			dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;		}		dst->table[--i].ctrl |= SG_CF_EOT;	}	return 0;}static void stex_internal_copy(struct scsi_cmnd *cmd,	const void *src, size_t *count, int sg_count, int direction){	size_t lcount;	size_t len;	void *s, *d, *base = NULL;	size_t offset;	if (*count > scsi_bufflen(cmd))		*count = scsi_bufflen(cmd);	lcount = *count;	while (lcount) {		len = lcount;		s = (void *)src;		offset = *count - lcount;		s += offset;		base = scsi_kmap_atomic_sg(scsi_sglist(cmd),					   sg_count, &offset, &len);		if (!base) {			*count -= lcount;			return;		}		d = base + offset;		if (direction == ST_TO_CMD)			memcpy(d, s, len);		else			memcpy(s, d, len);		lcount -= len;		scsi_kunmap_atomic_sg(base);	}}static int stex_direct_copy(struct scsi_cmnd *cmd,	const void *src, size_t count){	size_t cp_len = count;	int n_elem = 0;

⌨️ 快捷键说明

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