📄 aic94xx_seq.c
字号:
sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; for (i = 0; i < SAS_ADDR_SIZE; i++) asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); /* Set the Bus Inactivity Time Limit Timer. */ asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); /* Enable SATA Port Multiplier. */ asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); /* Initialize Interrupt Vector[0-10] address in Mode 3. * See the comment on CSEQ_INT_* */ asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); /* * Program the Link LED control, applicable only for * Chip Rev. B or later. */ asd_write_reg_dword(asd_ha, LmCONTROL(lseq), (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); /* Set the Align Rate for SAS and STP mode. */ asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT);}/** * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox * @asd_ha: pointer to host adapter struct */static void asd_post_init_cseq(struct asd_ha_struct *asd_ha){ int i; for (i = 0; i < 8; i++) asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); for (i = 0; i < 8; i++) asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); /* Reset the external interrupt arbiter. */ asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL);}/** * asd_init_ddb_0 -- initialize DDB 0 * @asd_ha: pointer to host adapter structure * * Initialize DDB site 0 which is used internally by the sequencer. */static void asd_init_ddb_0(struct asd_ha_struct *asd_ha){ int i; /* Zero out the DDB explicitly */ for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) asd_ddbsite_write_dword(asd_ha, 0, i, 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), asd_ha->hw_prof.max_ddbs-1); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); asd_ddbsite_write_word(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), asd_ha->hw_prof.num_phys * 2); asd_ddbsite_write_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); asd_ddbsite_write_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); asd_ddbsite_write_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); /* DDB 0 is reserved */ set_bit(0, asd_ha->hw_prof.ddb_bitmap);}static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha){ unsigned int i; unsigned int ddb_site; for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0);}/** * asd_seq_setup_seqs -- setup and initialize central and link sequencers * @asd_ha: pointer to host adapter structure */static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha){ int lseq; u8 lseq_mask; /* Initialize DDB sites */ asd_seq_init_ddb_sites(asd_ha); /* Initialize SCB sites. Done first to compute some values which * the rest of the init code depends on. */ asd_init_scb_sites(asd_ha); /* Initialize CSEQ Scratch RAM registers. */ asd_init_cseq_scratch(asd_ha); /* Initialize LmSEQ Scratch RAM registers. */ asd_init_lseq_scratch(asd_ha); /* Initialize CSEQ CIO registers. */ asd_init_cseq_cio(asd_ha); asd_init_ddb_0(asd_ha); /* Initialize LmSEQ CIO registers. */ lseq_mask = asd_ha->hw_prof.enabled_phys; for_each_sequencer(lseq_mask, lseq_mask, lseq) asd_init_lseq_cio(asd_ha, lseq); asd_post_init_cseq(asd_ha);}/** * asd_seq_start_cseq -- start the central sequencer, CSEQ * @asd_ha: pointer to host adapter structure */static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha){ /* Reset the ARP2 instruction to location zero. */ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); /* Unpause the CSEQ */ return asd_unpause_cseq(asd_ha);}/** * asd_seq_start_lseq -- start a link sequencer * @asd_ha: pointer to host adapter structure * @lseq: the link sequencer of interest */static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq){ /* Reset the ARP2 instruction to location zero. */ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); /* Unpause the LmSEQ */ return asd_seq_unpause_lseq(asd_ha, lseq);}int asd_release_firmware(void){ if (sequencer_fw) release_firmware(sequencer_fw); return 0;}static int asd_request_firmware(struct asd_ha_struct *asd_ha){ int err, i; struct sequencer_file_header header, *hdr_ptr; u32 csum = 0; u16 *ptr_cseq_vecs, *ptr_lseq_vecs; if (sequencer_fw) /* already loaded */ return 0; err = request_firmware(&sequencer_fw, SAS_RAZOR_SEQUENCER_FW_FILE, &asd_ha->pcidev->dev); if (err) return err; hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data; header.csum = le32_to_cpu(hdr_ptr->csum); header.major = le32_to_cpu(hdr_ptr->major); header.minor = le32_to_cpu(hdr_ptr->minor); header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); for (i = sizeof(header.csum); i < sequencer_fw->size; i++) csum += sequencer_fw->data[i]; if (csum != header.csum) { asd_printk("Firmware file checksum mismatch\n"); return -EINVAL; } if (header.cseq_table_size != CSEQ_NUM_VECS || header.lseq_table_size != LSEQ_NUM_VECS) { asd_printk("Firmware file table size mismatch\n"); return -EINVAL; } asd_printk("Found sequencer Firmware version %d.%d (%s)\n", header.major, header.minor, hdr_ptr->version); if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { asd_printk("Firmware Major Version Mismatch;" "driver requires version %d.X", SAS_RAZOR_SEQUENCER_FW_MAJOR); return -EINVAL; } ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; mode2_task = header.mode2_task; cseq_idle_loop = header.cseq_idle_loop; lseq_idle_loop = header.lseq_idle_loop; for (i = 0; i < CSEQ_NUM_VECS; i++) cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); for (i = 0; i < LSEQ_NUM_VECS; i++) lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); cseq_code = &sequencer_fw->data[header.cseq_code_offset]; cseq_code_size = header.cseq_code_size; lseq_code = &sequencer_fw->data[header.lseq_code_offset]; lseq_code_size = header.lseq_code_size; return 0;}int asd_init_seqs(struct asd_ha_struct *asd_ha){ int err; err = asd_request_firmware(asd_ha); if (err) { asd_printk("Failed to load sequencer firmware file %s, error %d\n", SAS_RAZOR_SEQUENCER_FW_FILE, err); return err; } err = asd_seq_download_seqs(asd_ha); if (err) { asd_printk("couldn't download sequencers for %s\n", pci_name(asd_ha->pcidev)); return err; } asd_seq_setup_seqs(asd_ha); return 0;}int asd_start_seqs(struct asd_ha_struct *asd_ha){ int err; u8 lseq_mask; int lseq; err = asd_seq_start_cseq(asd_ha); if (err) { asd_printk("couldn't start CSEQ for %s\n", pci_name(asd_ha->pcidev)); return err; } lseq_mask = asd_ha->hw_prof.enabled_phys; for_each_sequencer(lseq_mask, lseq_mask, lseq) { err = asd_seq_start_lseq(asd_ha, lseq); if (err) { asd_printk("coudln't start LSEQ %d for %s\n", lseq, pci_name(asd_ha->pcidev)); return err; } } return 0;}/** * asd_update_port_links -- update port_map_by_links and phy_is_up * @sas_phy: pointer to the phy which has been added to a port * * 1) When a link reset has completed and we got BYTES DMAED with a * valid frame we call this function for that phy, to indicate that * the phy is up, i.e. we update the phy_is_up in DDB 0. The * sequencer checks phy_is_up when pending SCBs are to be sent, and * when an open address frame has been received. * * 2) When we know of ports, we call this function to update the map * of phys participaing in that port, i.e. we update the * port_map_by_links in DDB 0. When a HARD_RESET primitive has been * received, the sequencer disables all phys in that port. * port_map_by_links is also used as the conn_mask byte in the * initiator/target port DDB. */void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy){ const u8 phy_mask = (u8) phy->asd_port->phy_mask; u8 phy_is_up; u8 mask; int i, err; unsigned long flags; spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); for_each_phy(phy_mask, mask, i) asd_ddbsite_write_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, port_map_by_links)+i,phy_mask); for (i = 0; i < 12; i++) { phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, phy_is_up)); err = asd_ddbsite_update_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, phy_is_up), phy_is_up, phy_is_up | phy_mask); if (!err) break; else if (err == -EFAULT) { asd_printk("phy_is_up: parity error in DDB 0\n"); break; } } spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); if (err) asd_printk("couldn't update DDB 0:error:%d\n", err);}MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -