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

📄 aic94xx_hwi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Aic94xx SAS/SATA driver hardware interface. * * 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 <linux/module.h>#include "aic94xx.h"#include "aic94xx_reg.h"#include "aic94xx_hwi.h"#include "aic94xx_seq.h"#include "aic94xx_dump.h"u32 MBAR0_SWB_SIZE;/* ---------- Initialization ---------- */static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha){	extern char sas_addr_str[];	/* If the user has specified a WWN it overrides other settings	 */	if (sas_addr_str[0] != '\0')		asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,					 sas_addr_str);	else if (asd_ha->hw_prof.sas_addr[0] != 0)		asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);}static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha){	int i;	for (i = 0; i < ASD_MAX_PHYS; i++) {		if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)			continue;		/* Set a phy's address only if it has none.		 */		ASD_DPRINTK("setting phy%d addr to %llx\n", i,			    SAS_ADDR(asd_ha->hw_prof.sas_addr));		memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,		       asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);	}}/* ---------- PHY initialization ---------- */static void asd_init_phy_identify(struct asd_phy *phy){	phy->identify_frame = phy->id_frm_tok->vaddr;	memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));	phy->identify_frame->dev_type = SAS_END_DEV;	if (phy->sas_phy.role & PHY_ROLE_INITIATOR)		phy->identify_frame->initiator_bits = phy->sas_phy.iproto;	if (phy->sas_phy.role & PHY_ROLE_TARGET)		phy->identify_frame->target_bits = phy->sas_phy.tproto;	memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,	       SAS_ADDR_SIZE);	phy->identify_frame->phy_id = phy->sas_phy.id;}static int asd_init_phy(struct asd_phy *phy){	struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;	struct asd_sas_phy *sas_phy = &phy->sas_phy;	sas_phy->enabled = 1;	sas_phy->class = SAS;	sas_phy->iproto = SAS_PROTO_ALL;	sas_phy->tproto = 0;	sas_phy->type = PHY_TYPE_PHYSICAL;	sas_phy->role = PHY_ROLE_INITIATOR;	sas_phy->oob_mode = OOB_NOT_CONNECTED;	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;	phy->id_frm_tok = asd_alloc_coherent(asd_ha,					     sizeof(*phy->identify_frame),					     GFP_KERNEL);	if (!phy->id_frm_tok) {		asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);		return -ENOMEM;	} else		asd_init_phy_identify(phy);	memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));	return 0;}static void asd_init_ports(struct asd_ha_struct *asd_ha){	int i;	spin_lock_init(&asd_ha->asd_ports_lock);	for (i = 0; i < ASD_MAX_PHYS; i++) {		struct asd_port *asd_port = &asd_ha->asd_ports[i];		memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE);		memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE);		asd_port->phy_mask = 0;		asd_port->num_phys = 0;	}}static int asd_init_phys(struct asd_ha_struct *asd_ha){	u8 i;	u8 phy_mask = asd_ha->hw_prof.enabled_phys;	for (i = 0; i < ASD_MAX_PHYS; i++) {		struct asd_phy *phy = &asd_ha->phys[i];		phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];		phy->asd_port = NULL;		phy->sas_phy.enabled = 0;		phy->sas_phy.id = i;		phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];		phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];		phy->sas_phy.ha = &asd_ha->sas_ha;		phy->sas_phy.lldd_phy = phy;	}	/* Now enable and initialize only the enabled phys. */	for_each_phy(phy_mask, phy_mask, i) {		int err = asd_init_phy(&asd_ha->phys[i]);		if (err)			return err;	}	return 0;}/* ---------- Sliding windows ---------- */static int asd_init_sw(struct asd_ha_struct *asd_ha){	struct pci_dev *pcidev = asd_ha->pcidev;	int err;	u32 v;	/* Unlock MBARs */	err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);	if (err) {		asd_printk("couldn't access conf. space of %s\n",			   pci_name(pcidev));		goto Err;	}	if (v)		err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);	if (err) {		asd_printk("couldn't write to MBAR_KEY of %s\n",			   pci_name(pcidev));		goto Err;	}	/* Set sliding windows A, B and C to point to proper internal	 * memory regions.	 */	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,			       REG_BASE_ADDR_CSEQCIO);	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);	asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;	asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;	asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;	MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;	if (!asd_ha->iospace) {		/* MBAR1 will point to OCM (On Chip Memory) */		pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);		asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;	}	spin_lock_init(&asd_ha->iolock);Err:	return err;}/* ---------- SCB initialization ---------- *//** * asd_init_scbs - manually allocate the first SCB. * @asd_ha: pointer to host adapter structure * * This allocates the very first SCB which would be sent to the * sequencer for execution.  Its bus address is written to * CSEQ_Q_NEW_POINTER, mode page 2, mode 8.  Since the bus address of * the _next_ scb to be DMA-ed to the host adapter is read from the last * SCB DMA-ed to the host adapter, we have to always stay one step * ahead of the sequencer and keep one SCB already allocated. */static int asd_init_scbs(struct asd_ha_struct *asd_ha){	struct asd_seq_data *seq = &asd_ha->seq;	int bitmap_bytes;	/* allocate the index array and bitmap */	asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;	asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*					     sizeof(void *), GFP_KERNEL);	if (!asd_ha->seq.tc_index_array)		return -ENOMEM;	bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);	asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);	if (!asd_ha->seq.tc_index_bitmap)		return -ENOMEM;	spin_lock_init(&seq->tc_index_lock);	seq->next_scb.size = sizeof(struct scb);	seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,					     &seq->next_scb.dma_handle);	if (!seq->next_scb.vaddr) {		kfree(asd_ha->seq.tc_index_bitmap);		kfree(asd_ha->seq.tc_index_array);		asd_ha->seq.tc_index_bitmap = NULL;		asd_ha->seq.tc_index_array = NULL;		return -ENOMEM;	}	seq->pending = 0;	spin_lock_init(&seq->pend_q_lock);	INIT_LIST_HEAD(&seq->pend_q);	return 0;}static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha){	asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;	asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;	ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",		    asd_ha->hw_prof.max_scbs,		    asd_ha->hw_prof.max_ddbs);}/* ---------- Done List initialization ---------- */static void asd_dl_tasklet_handler(unsigned long);static int asd_init_dl(struct asd_ha_struct *asd_ha){	asd_ha->seq.actual_dl		= asd_alloc_coherent(asd_ha,			     ASD_DL_SIZE * sizeof(struct done_list_struct),				     GFP_KERNEL);	if (!asd_ha->seq.actual_dl)		return -ENOMEM;	asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;	asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;	asd_ha->seq.dl_next = 0;	tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,		     (unsigned long) asd_ha);	return 0;}/* ---------- EDB and ESCB init ---------- */static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags){	struct asd_seq_data *seq = &asd_ha->seq;	int i;	seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);	if (!seq->edb_arr)		return -ENOMEM;	for (i = 0; i < seq->num_edbs; i++) {		seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,						     gfp_flags);		if (!seq->edb_arr[i])			goto Err_unroll;		memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);	}	ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);	return 0;Err_unroll:	for (i-- ; i >= 0; i--)		asd_free_coherent(asd_ha, seq->edb_arr[i]);	kfree(seq->edb_arr);	seq->edb_arr = NULL;	return -ENOMEM;}static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,			   gfp_t gfp_flags){	struct asd_seq_data *seq = &asd_ha->seq;	struct asd_ascb *escb;	int i, escbs;	seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),				gfp_flags);	if (!seq->escb_arr)		return -ENOMEM;	escbs = seq->num_escbs;	escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);	if (!escb) {		asd_printk("couldn't allocate list of escbs\n");		goto Err;	}	seq->num_escbs -= escbs;  /* subtract what was not allocated */	ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);	for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,							       struct asd_ascb,							       list)) {		seq->escb_arr[i] = escb;		escb->scb->header.opcode = EMPTY_SCB;	}	return 0;Err:	kfree(seq->escb_arr);	seq->escb_arr = NULL;	return -ENOMEM;}static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha){	struct asd_seq_data *seq = &asd_ha->seq;	int i, k, z = 0;	for (i = 0; i < seq->num_escbs; i++) {		struct asd_ascb *ascb = seq->escb_arr[i];		struct empty_scb *escb = &ascb->scb->escb;		ascb->edb_index = z;		escb->num_valid = ASD_EDBS_PER_SCB;		for (k = 0; k < ASD_EDBS_PER_SCB; k++) {			struct sg_el *eb = &escb->eb[k];			struct asd_dma_tok *edb = seq->edb_arr[z++];			memset(eb, 0, sizeof(*eb));			eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));			eb->size = cpu_to_le32(((u32) edb->size));		}	}}/** * asd_init_escbs -- allocate and initialize empty scbs * @asd_ha: pointer to host adapter structure * * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers. * They transport sense data, etc. */static int asd_init_escbs(struct asd_ha_struct *asd_ha){	struct asd_seq_data *seq = &asd_ha->seq;	int err = 0;	/* Allocate two empty data buffers (edb) per sequencer. */	int edbs = 2*(1+asd_ha->hw_prof.num_phys);	seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;	seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;	err = asd_alloc_edbs(asd_ha, GFP_KERNEL);	if (err) {		asd_printk("couldn't allocate edbs\n");		return err;	}	err = asd_alloc_escbs(asd_ha, GFP_KERNEL);	if (err) {		asd_printk("couldn't allocate escbs\n");		return err;	}	asd_assign_edbs2escbs(asd_ha);	/* In order to insure that normal SCBs do not overfill sequencer	 * memory and leave no space for escbs (halting condition),	 * we increment pending here by the number of escbs.  However,	 * escbs are never pending.	 */	seq->pending   = seq->num_escbs;	seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;	return 0;}/* ---------- HW initialization ---------- *//** * asd_chip_hardrst -- hard reset the chip * @asd_ha: pointer to host adapter structure * * This takes 16 cycles and is synchronous to CFCLK, which runs * at 200 MHz, so this should take at most 80 nanoseconds. */int asd_chip_hardrst(struct asd_ha_struct *asd_ha){	int i;	int count = 100;	u32 reg;	for (i = 0 ; i < 4 ; i++) {		asd_write_reg_dword(asd_ha, COMBIST, HARDRST);	}	do {		udelay(1);		reg = asd_read_reg_dword(asd_ha, CHIMINT);		if (reg & HARDRSTDET) {			asd_write_reg_dword(asd_ha, CHIMINT,					    HARDRSTDET|PORRSTDET);			return 0;		}	} while (--count > 0);	return -ENODEV;}/** * asd_init_chip -- initialize the chip * @asd_ha: pointer to host adapter structure * * Hard resets the chip, disables HA interrupts, downloads the sequnecer * microcode and starts the sequencers.  The caller has to explicitly * enable HA interrupts with asd_enable_ints(asd_ha). */static int asd_init_chip(struct asd_ha_struct *asd_ha){	int err;	err = asd_chip_hardrst(asd_ha);	if (err) {		asd_printk("couldn't hard reset %s\n",			    pci_name(asd_ha->pcidev));

⌨️ 快捷键说明

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