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

📄 aic94xx_hwi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		goto out;	}	asd_disable_ints(asd_ha);	err = asd_init_seqs(asd_ha);	if (err) {		asd_printk("couldn't init seqs for %s\n",			   pci_name(asd_ha->pcidev));		goto out;	}	err = asd_start_seqs(asd_ha);	if (err) {		asd_printk("coudln't start seqs for %s\n",			   pci_name(asd_ha->pcidev));		goto out;	}out:	return err;}#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))static int max_devs = 0;module_param_named(max_devs, max_devs, int, S_IRUGO);MODULE_PARM_DESC(max_devs, "\n"	"\tMaximum number of SAS devices to support (not LUs).\n"	"\tDefault: 2176, Maximum: 65663.\n");static int max_cmnds = 0;module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);MODULE_PARM_DESC(max_cmnds, "\n"	"\tMaximum number of commands queuable.\n"	"\tDefault: 512, Maximum: 66047.\n");static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha){	unsigned long dma_addr = OCM_BASE_ADDR;	u32 d;	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;	asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);	d |= 4;	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);	asd_ha->hw_prof.max_ddbs += MAX_DEVS;}static int asd_extend_devctx(struct asd_ha_struct *asd_ha){	dma_addr_t dma_handle;	unsigned long dma_addr;	u32 d;	int size;	asd_extend_devctx_ocm(asd_ha);	asd_ha->hw_prof.ddb_ext = NULL;	if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {		max_devs = asd_ha->hw_prof.max_ddbs;		return 0;	}	size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;	asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);	if (!asd_ha->hw_prof.ddb_ext) {		asd_printk("couldn't allocate memory for %d devices\n",			   max_devs);		max_devs = asd_ha->hw_prof.max_ddbs;		return -ENOMEM;	}	dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;	dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;	dma_handle = (dma_addr_t) dma_addr;	asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);	d &= ~4;	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);	asd_ha->hw_prof.max_ddbs = max_devs;	return 0;}static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha){	dma_addr_t dma_handle;	unsigned long dma_addr;	u32 d;	int size;	asd_ha->hw_prof.scb_ext = NULL;	if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {		max_cmnds = asd_ha->hw_prof.max_scbs;		return 0;	}	size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;	asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);	if (!asd_ha->hw_prof.scb_ext) {		asd_printk("couldn't allocate memory for %d commands\n",			   max_cmnds);		max_cmnds = asd_ha->hw_prof.max_scbs;		return -ENOMEM;	}	dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;	dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);	dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;	dma_handle = (dma_addr_t) dma_addr;	asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);	d &= ~1;	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);	asd_ha->hw_prof.max_scbs = max_cmnds;	return 0;}/** * asd_init_ctxmem -- initialize context memory * asd_ha: pointer to host adapter structure * * This function sets the maximum number of SCBs and * DDBs which can be used by the sequencer.  This is normally * 512 and 128 respectively.  If support for more SCBs or more DDBs * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are * initialized here to extend context memory to point to host memory, * thus allowing unlimited support for SCBs and DDBs -- only limited * by host memory. */static int asd_init_ctxmem(struct asd_ha_struct *asd_ha){	int bitmap_bytes;	asd_get_max_scb_ddb(asd_ha);	asd_extend_devctx(asd_ha);	asd_extend_cmdctx(asd_ha);	/* The kernel wants bitmaps to be unsigned long sized. */	bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);	asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);	if (!asd_ha->hw_prof.ddb_bitmap)		return -ENOMEM;	spin_lock_init(&asd_ha->hw_prof.ddb_lock);	return 0;}int asd_init_hw(struct asd_ha_struct *asd_ha){	int err;	u32 v;	err = asd_init_sw(asd_ha);	if (err)		return err;	err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);	if (err) {		asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",			   pci_name(asd_ha->pcidev));		return err;	}	pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,					v | SC_TMR_DIS);	if (err) {		asd_printk("couldn't disable split completion timer of %s\n",			   pci_name(asd_ha->pcidev));		return err;	}	err = asd_read_ocm(asd_ha);	if (err) {		asd_printk("couldn't read ocm(%d)\n", err);		/* While suspicios, it is not an error that we		 * couldn't read the OCM. */	}	err = asd_read_flash(asd_ha);	if (err) {		asd_printk("couldn't read flash(%d)\n", err);		/* While suspicios, it is not an error that we		 * couldn't read FLASH memory.		 */	}	asd_init_ctxmem(asd_ha);	asd_get_user_sas_addr(asd_ha);	if (!asd_ha->hw_prof.sas_addr[0]) {		asd_printk("No SAS Address provided for %s\n",			   pci_name(asd_ha->pcidev));		err = -ENODEV;		goto Out;	}	asd_propagate_sas_addr(asd_ha);	err = asd_init_phys(asd_ha);	if (err) {		asd_printk("couldn't initialize phys for %s\n",			    pci_name(asd_ha->pcidev));		goto Out;	}	asd_init_ports(asd_ha);	err = asd_init_scbs(asd_ha);	if (err) {		asd_printk("couldn't initialize scbs for %s\n",			    pci_name(asd_ha->pcidev));		goto Out;	}	err = asd_init_dl(asd_ha);	if (err) {		asd_printk("couldn't initialize the done list:%d\n",			    err);		goto Out;	}	err = asd_init_escbs(asd_ha);	if (err) {		asd_printk("couldn't initialize escbs\n");		goto Out;	}	err = asd_init_chip(asd_ha);	if (err) {		asd_printk("couldn't init the chip\n");		goto Out;	}Out:	return err;}/* ---------- Chip reset ---------- *//** * asd_chip_reset -- reset the host adapter, etc * @asd_ha: pointer to host adapter structure of interest * * Called from the ISR.  Hard reset the chip.  Let everything * timeout.  This should be no different than hot-unplugging the * host adapter.  Once everything times out we'll init the chip with * a call to asd_init_chip() and enable interrupts with asd_enable_ints(). * XXX finish. */static void asd_chip_reset(struct asd_ha_struct *asd_ha){	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;	ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));	asd_chip_hardrst(asd_ha);	sas_ha->notify_ha_event(sas_ha, HAE_RESET);}/* ---------- Done List Routines ---------- */static void asd_dl_tasklet_handler(unsigned long data){	struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;	struct asd_seq_data *seq = &asd_ha->seq;	unsigned long flags;	while (1) {		struct done_list_struct *dl = &seq->dl[seq->dl_next];		struct asd_ascb *ascb;		if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)			break;		/* find the aSCB */		spin_lock_irqsave(&seq->tc_index_lock, flags);		ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));		spin_unlock_irqrestore(&seq->tc_index_lock, flags);		if (unlikely(!ascb)) {			ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");			goto next_1;		} else if (ascb->scb->header.opcode == EMPTY_SCB) {			goto out;		} else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {			goto next_1;		}		spin_lock_irqsave(&seq->pend_q_lock, flags);		list_del_init(&ascb->list);		seq->pending--;		spin_unlock_irqrestore(&seq->pend_q_lock, flags);	out:		ascb->tasklet_complete(ascb, dl);	next_1:		seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);		if (!seq->dl_next)			seq->dl_toggle ^= DL_TOGGLE_MASK;	}}/* ---------- Interrupt Service Routines ---------- *//** * asd_process_donelist_isr -- schedule processing of done list entries * @asd_ha: pointer to host adapter structure */static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha){	tasklet_schedule(&asd_ha->seq.dl_tasklet);}/** * asd_com_sas_isr -- process device communication interrupt (COMINT) * @asd_ha: pointer to host adapter structure */static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha){	u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);	/* clear COMSTAT int */	asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);	if (comstat & CSBUFPERR) {		asd_printk("%s: command/status buffer dma parity error\n",			   pci_name(asd_ha->pcidev));	} else if (comstat & CSERR) {		int i;		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);		dmaerr &= 0xFF;		asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "			   "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",			   pci_name(asd_ha->pcidev),			   dmaerr,			   asd_read_reg_dword(asd_ha, CSDMAADR),			   asd_read_reg_dword(asd_ha, CSDMAADR+4));		asd_printk("CSBUFFER:\n");		for (i = 0; i < 8; i++) {			asd_printk("%08x %08x %08x %08x\n",				   asd_read_reg_dword(asd_ha, CSBUFFER),				   asd_read_reg_dword(asd_ha, CSBUFFER+4),				   asd_read_reg_dword(asd_ha, CSBUFFER+8),				   asd_read_reg_dword(asd_ha, CSBUFFER+12));		}		asd_dump_seq_state(asd_ha, 0);	} else if (comstat & OVLYERR) {		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);		dmaerr = (dmaerr >> 8) & 0xFF;		asd_printk("%s: overlay dma error:0x%x\n",			   pci_name(asd_ha->pcidev),			   dmaerr);	}	asd_chip_reset(asd_ha);}static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus){	static const char *halt_code[256] = {		"UNEXPECTED_INTERRUPT0",		"UNEXPECTED_INTERRUPT1",		"UNEXPECTED_INTERRUPT2",		"UNEXPECTED_INTERRUPT3",		"UNEXPECTED_INTERRUPT4",		"UNEXPECTED_INTERRUPT5",		"UNEXPECTED_INTERRUPT6",		"UNEXPECTED_INTERRUPT7",		"UNEXPECTED_INTERRUPT8",		"UNEXPECTED_INTERRUPT9",		"UNEXPECTED_INTERRUPT10",		[11 ... 19] = "unknown[11,19]",		"NO_FREE_SCB_AVAILABLE",		"INVALID_SCB_OPCODE",		"INVALID_MBX_OPCODE",		"INVALID_ATA_STATE",		"ATA_QUEUE_FULL",		"ATA_TAG_TABLE_FAULT",		"ATA_TAG_MASK_FAULT",		"BAD_LINK_QUEUE_STATE",		"DMA2CHIM_QUEUE_ERROR",		"EMPTY_SCB_LIST_FULL",		"unknown[30]",		"IN_USE_SCB_ON_FREE_LIST",		"BAD_OPEN_WAIT_STATE",		"INVALID_STP_AFFILIATION",		"unknown[34]",		"EXEC_QUEUE_ERROR",		"TOO_MANY_EMPTIES_NEEDED",		"EMPTY_REQ_QUEUE_ERROR",		"Q_MONIRTT_MGMT_ERROR",		"TARGET_MODE_FLOW_ERROR",		"DEVICE_QUEUE_NOT_FOUND",		"START_IRTT_TIMER_ERROR",		"ABORT_TASK_ILLEGAL_REQ",		[43 ... 255] = "unknown[43,255]"	};	if (dchstatus & CSEQINT) {		u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);		if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {			asd_printk("%s: CSEQ arp2int:0x%x\n",				   pci_name(asd_ha->pcidev),				   arp2int);		} else if (arp2int & ARP2HALTC)			asd_printk("%s: CSEQ halted: %s\n",				   pci_name(asd_ha->pcidev),				   halt_code[(arp2int>>16)&0xFF]);		else			asd_printk("%s: CARP2INT:0x%x\n",				   pci_name(asd_ha->pcidev),				   arp2int);	}	if (dchstatus & LSEQINT_MASK) {		int lseq;		u8  lseq_mask = dchstatus & LSEQINT_MASK;		for_each_sequencer(lseq_mask, lseq_mask, lseq) {			u32 arp2int = asd_read_reg_dword(asd_ha,							 LmARP2INT(lseq));			if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR				       | ARP2CIOPERR)) {				asd_printk("%s: LSEQ%d arp2int:0x%x\n",					   pci_name(asd_ha->pcidev),					   lseq, arp2int);				/* XXX we should only do lseq reset */			} else if (arp2int & ARP2HALTC)				asd_printk("%s: LSEQ%d halted: %s\n",					   pci_name(asd_ha->pcidev),					   lseq,halt_code[(arp2int>>16)&0xFF]);			else				asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",					   pci_name(asd_ha->pcidev), lseq,					   arp2int);		}	}	asd_chip_reset(asd_ha);}/** * asd_dch_sas_isr -- process device channel interrupt (DEVINT) * @asd_ha: pointer to host adapter structure */static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha){	u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);	if (dchstatus & CFIFTOERR) {		asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));		asd_chip_reset(asd_ha);	} else		asd_arp2_err(asd_ha, dchstatus);}/** * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR) * @asd_ha: pointer to host adapter structure */static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha){	u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);	if (!(stat0r & ASIERR)) {

⌨️ 快捷键说明

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