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

📄 aic94xx_sds.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Aic94xx SAS/SATA driver access to shared data structures and memory * maps. * * Copyright (C) 2005 Adaptec, Inc.  All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * This file is licensed under GPLv2. * * This file is part of the aic94xx driver. * * The aic94xx driver 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. * * The aic94xx driver 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. * * You should have received a copy of the GNU General Public License * along with the aic94xx driver; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#include <linux/pci.h>#include <linux/delay.h>#include "aic94xx.h"#include "aic94xx_reg.h"/* ---------- OCM stuff ---------- */struct asd_ocm_dir_ent {	u8 type;	u8 offs[3];	u8 _r1;	u8 size[3];} __attribute__ ((packed));struct asd_ocm_dir {	char sig[2];	u8   _r1[2];	u8   major;          /* 0 */	u8   minor;          /* 0 */	u8   _r2;	u8   num_de;	struct asd_ocm_dir_ent entry[15];} __attribute__ ((packed));#define	OCM_DE_OCM_DIR			0x00#define	OCM_DE_WIN_DRVR			0x01#define	OCM_DE_BIOS_CHIM		0x02#define	OCM_DE_RAID_ENGN		0x03#define	OCM_DE_BIOS_INTL		0x04#define	OCM_DE_BIOS_CHIM_OSM		0x05#define	OCM_DE_BIOS_CHIM_DYNAMIC	0x06#define	OCM_DE_ADDC2C_RES0		0x07#define	OCM_DE_ADDC2C_RES1		0x08#define	OCM_DE_ADDC2C_RES2		0x09#define	OCM_DE_ADDC2C_RES3		0x0A#define OCM_INIT_DIR_ENTRIES	5/****************************************************************************  OCM directory default***************************************************************************/static struct asd_ocm_dir OCMDirInit ={	.sig = {0x4D, 0x4F},	/* signature */	.num_de = OCM_INIT_DIR_ENTRIES,	/* no. of directory entries */};/****************************************************************************  OCM directory Entries default***************************************************************************/static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] ={	{		.type = (OCM_DE_ADDC2C_RES0),	/* Entry type  */		.offs = {128},			/* Offset */		.size = {0, 4},			/* size */	},	{		.type = (OCM_DE_ADDC2C_RES1),	/* Entry type  */		.offs = {128, 4},		/* Offset */		.size = {0, 4},			/* size */	},	{		.type = (OCM_DE_ADDC2C_RES2),	/* Entry type  */		.offs = {128, 8},		/* Offset */		.size = {0, 4},			/* size */	},	{		.type = (OCM_DE_ADDC2C_RES3),	/* Entry type  */		.offs = {128, 12},		/* Offset */		.size = {0, 4},			/* size */	},	{		.type = (OCM_DE_WIN_DRVR),	/* Entry type  */		.offs = {128, 16},		/* Offset */		.size = {128, 235, 1},		/* size */	},};struct asd_bios_chim_struct {	char sig[4];	u8   major;          /* 1 */	u8   minor;          /* 0 */	u8   bios_major;	u8   bios_minor;	__le32  bios_build;	u8   flags;	u8   pci_slot;	__le16  ue_num;	__le16  ue_size;	u8  _r[14];	/* The unit element array is right here.	 */} __attribute__ ((packed));/** * asd_read_ocm_seg - read an on chip memory (OCM) segment * @asd_ha: pointer to the host adapter structure * @buffer: where to write the read data * @offs: offset into OCM where to read from * @size: how many bytes to read * * Return the number of bytes not read. Return 0 on success. */static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,			    u32 offs, int size){	u8 *p = buffer;	if (unlikely(asd_ha->iospace))		asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);	else {		for ( ; size > 0; size--, offs++, p++)			*p = asd_read_ocm_byte(asd_ha, offs);	}	return size;}static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,			    struct asd_ocm_dir *dir, u32 offs){	int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));	if (err) {		ASD_DPRINTK("couldn't read ocm segment\n");		return err;	}	if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {		ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",			    dir->sig[0], dir->sig[1]);		return -ENOENT;	}	if (dir->major != 0) {		asd_printk("unsupported major version of ocm dir:0x%x\n",			   dir->major);		return -ENOENT;	}	dir->num_de &= 0xf;	return 0;}/** * asd_write_ocm_seg - write an on chip memory (OCM) segment * @asd_ha: pointer to the host adapter structure * @buffer: where to read the write data * @offs: offset into OCM to write to * @size: how many bytes to write * * Return the number of bytes not written. Return 0 on success. */static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,			    u32 offs, int size){	u8 *p = buffer;	if (unlikely(asd_ha->iospace))		asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);	else {		for ( ; size > 0; size--, offs++, p++)			asd_write_ocm_byte(asd_ha, offs, *p);	}	return;}#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,			      u32 *offs, u32 *size){	int i;	struct asd_ocm_dir_ent *ent;	for (i = 0; i < dir->num_de; i++) {		if (dir->entry[i].type == type)			break;	}	if (i >= dir->num_de)		return -ENOENT;	ent = &dir->entry[i];	*offs = (u32) THREE_TO_NUM(ent->offs);	*size = (u32) THREE_TO_NUM(ent->size);	return 0;}#define OCM_BIOS_CHIM_DE  2#define BC_BIOS_PRESENT   1static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,			     struct asd_ocm_dir *dir){	int err;	struct asd_bios_chim_struct *bc_struct;	u32 offs, size;	err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);	if (err) {		ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");		goto out;	}	err = -ENOMEM;	bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);	if (!bc_struct) {		asd_printk("no memory for bios_chim struct\n");		goto out;	}	err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,			       sizeof(*bc_struct));	if (err) {		ASD_DPRINTK("couldn't read ocm segment\n");		goto out2;	}	if (strncmp(bc_struct->sig, "SOIB", 4)	    && strncmp(bc_struct->sig, "IPSA", 4)) {		ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",			    bc_struct->sig[0], bc_struct->sig[1],			    bc_struct->sig[2], bc_struct->sig[3]);		err = -ENOENT;		goto out2;	}	if (bc_struct->major != 1) {		asd_printk("BIOS_CHIM unsupported major version:0x%x\n",			   bc_struct->major);		err = -ENOENT;		goto out2;	}	if (bc_struct->flags & BC_BIOS_PRESENT) {		asd_ha->hw_prof.bios.present = 1;		asd_ha->hw_prof.bios.maj = bc_struct->bios_major;		asd_ha->hw_prof.bios.min = bc_struct->bios_minor;		asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);		ASD_DPRINTK("BIOS present (%d,%d), %d\n",			    asd_ha->hw_prof.bios.maj,			    asd_ha->hw_prof.bios.min,			    asd_ha->hw_prof.bios.bld);	}	asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);	asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);	ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,		    asd_ha->hw_prof.ue.size);	size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;	if (size > 0) {		err = -ENOMEM;		asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);		if (!asd_ha->hw_prof.ue.area)			goto out2;		err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,				       offs + sizeof(*bc_struct), size);		if (err) {			kfree(asd_ha->hw_prof.ue.area);			asd_ha->hw_prof.ue.area = NULL;			asd_ha->hw_prof.ue.num  = 0;			asd_ha->hw_prof.ue.size = 0;			ASD_DPRINTK("couldn't read ue entries(%d)\n", err);		}	}out2:	kfree(bc_struct);out:	return err;}static voidasd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha){	int i;	/* Zero OCM */	for (i = 0; i < OCM_MAX_SIZE; i += 4)		asd_write_ocm_dword(asd_ha, i, 0);	/* Write Dir */	asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,			  sizeof(struct asd_ocm_dir));	/* Write Dir Entries */	for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)		asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],				  sizeof(struct asd_ocm_dir) +				  (i * sizeof(struct asd_ocm_dir_ent))				  , sizeof(struct asd_ocm_dir_ent));}static intasd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha){	struct pci_dev *pcidev = asd_ha->pcidev;	u32 reg;	int err = 0;	u32 v;	/* check if OCM has been initialized by BIOS */	reg = asd_read_reg_dword(asd_ha, EXSICNFGR);	if (!(reg & OCMINITIALIZED)) {		err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);		if (err) {			asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",					pci_name(pcidev));			goto out;		}		printk(KERN_INFO "OCM is not initialized by BIOS,"		       "reinitialize it and ignore it, current IntrptStatus"		       "is 0x%x\n", v);		if (v)			err = pci_write_config_dword(pcidev,						     PCIC_INTRPT_STAT, v);		if (err) {			asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",					pci_name(pcidev));			goto out;		}		asd_hwi_initialize_ocm_dir(asd_ha);	}out:	return err;}/** * asd_read_ocm - read on chip memory (OCM) * @asd_ha: pointer to the host adapter structure */int asd_read_ocm(struct asd_ha_struct *asd_ha){	int err;	struct asd_ocm_dir *dir;	if (asd_hwi_check_ocm_access(asd_ha))		return -1;	dir = kmalloc(sizeof(*dir), GFP_KERNEL);	if (!dir) {		asd_printk("no memory for ocm dir\n");		return -ENOMEM;	}	err = asd_read_ocm_dir(asd_ha, dir, 0);	if (err)		goto out;	err = asd_get_bios_chim(asd_ha, dir);out:	kfree(dir);	return err;}/* ---------- FLASH stuff ---------- */#define FLASH_RESET			0xF0#define ASD_FLASH_SIZE                  0x200000#define FLASH_DIR_COOKIE                "*** ADAPTEC FLASH DIRECTORY *** "#define FLASH_NEXT_ENTRY_OFFS		0x2000#define FLASH_MAX_DIR_ENTRIES		32#define FLASH_DE_TYPE_MASK              0x3FFFFFFF#define FLASH_DE_MS                     0x120#define FLASH_DE_CTRL_A_USER            0xE0struct asd_flash_de {	__le32   type;	__le32   offs;	__le32   pad_size;	__le32   image_size;	__le32   chksum;	u8       _r[12];	u8       version[32];} __attribute__ ((packed));struct asd_flash_dir {	u8    cookie[32];	__le32   rev;		  /* 2 */	__le32   chksum;	__le32   chksum_antidote;	__le32   bld;	u8    bld_id[32];	  /* build id data */	u8    ver_data[32];	  /* date and time of build */	__le32   ae_mask;	__le32   v_mask;	__le32   oc_mask;	u8    _r[20];	struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];} __attribute__ ((packed));struct asd_manuf_sec {	char  sig[2];		  /* 'S', 'M' */	u16   offs_next;	u8    maj;           /* 0 */	u8    min;           /* 0 */	u16   chksum;	u16   size;	u8    _r[6];	u8    sas_addr[SAS_ADDR_SIZE];	u8    pcba_sn[ASD_PCBA_SN_SIZE];	/* Here start the other segments */	u8    linked_list[0];} __attribute__ ((packed));struct asd_manuf_phy_desc {	u8    state;         /* low 4 bits */#define MS_PHY_STATE_ENABLED    0#define MS_PHY_STATE_REPORTED   1#define MS_PHY_STATE_HIDDEN     2	u8    phy_id;	u16   _r;	u8    phy_control_0; /* mode 5 reg 0x160 */	u8    phy_control_1; /* mode 5 reg 0x161 */	u8    phy_control_2; /* mode 5 reg 0x162 */	u8    phy_control_3; /* mode 5 reg 0x163 */} __attribute__ ((packed));struct asd_manuf_phy_param {	char  sig[2];		  /* 'P', 'M' */	u16   next;	u8    maj;           /* 0 */	u8    min;           /* 2 */	u8    num_phy_desc;  /* 8 */	u8    phy_desc_size; /* 8 */	u8    _r[3];	u8    usage_model_id;	u32   _r2;	struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];} __attribute__ ((packed));#if 0static const char *asd_sb_type[] = {	"unknown",	"SGPIO",	[2 ... 0x7F] = "unknown",	[0x80] = "ADPT_I2C",	[0x81 ... 0xFF] = "VENDOR_UNIQUExx"};#endifstruct asd_ms_sb_desc {	u8    type;	u8    node_desc_index;	u8    conn_desc_index;	u8    _recvd[0];} __attribute__ ((packed));#if 0static const char *asd_conn_type[] = {	[0 ... 7] = "unknown",	"SFF8470",	"SFF8482",	"SFF8484",	[0x80] = "PCIX_DAUGHTER0",	[0x81] = "SAS_DAUGHTER0",	[0x82 ... 0xFF] = "VENDOR_UNIQUExx"};static const char *asd_conn_location[] = {	"unknown",	"internal",	"external",	"board_to_board",};#endifstruct asd_ms_conn_desc {	u8    type;	u8    location;	u8    num_sideband_desc;	u8    size_sideband_desc;	u32   _resvd;	u8    name[16];	struct asd_ms_sb_desc sb_desc[0];} __attribute__ ((packed));struct asd_nd_phy_desc {	u8    vp_attch_type;	u8    attch_specific[0];} __attribute__ ((packed));#if 0static const char *asd_node_type[] = {	"IOP",	"IO_CONTROLLER",	"EXPANDER",	"PORT_MULTIPLIER",	"PORT_MULTIPLEXER",	"MULTI_DROP_I2C_BUS",};#endifstruct asd_ms_node_desc {	u8    type;	u8    num_phy_desc;	u8    size_phy_desc;	u8    _resvd;	u8    name[16];	struct asd_nd_phy_desc phy_desc[0];} __attribute__ ((packed));struct asd_ms_conn_map {	char  sig[2];		  /* 'M', 'C' */	__le16 next;	u8    maj;		  /* 0 */	u8    min;		  /* 0 */	__le16 cm_size;		  /* size of this struct */	u8    num_conn;	u8    conn_size;	u8    num_nodes;	u8    usage_model_id;	u32   _resvd;	struct asd_ms_conn_desc conn_desc[0];	struct asd_ms_node_desc node_desc[0];} __attribute__ ((packed));struct asd_ctrla_phy_entry {	u8    sas_addr[SAS_ADDR_SIZE];	u8    sas_link_rates;  /* max in hi bits, min in low bits */	u8    flags;

⌨️ 快捷键说明

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