📄 aic94xx_hwi.c
字号:
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 + -