📄 aic94xx_sds.c
字号:
/* * 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 + -