📄 fsl_sata.c
字号:
/* Wait no active */ if (ata_wait_register(®->car, (1 << tag), 0, 10000)) printf("Wait no active time out\n\r"); /* Issue command */ if (!(in_le32(®->cqr) & (1 << tag))) { val32 = 1 << tag; out_le32(®->cqr, val32); } /* Wait command completed for 10s */ if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { if (!is_ncq) printf("Non-NCQ command time out\n\r"); else printf("NCQ command time out\n\r"); } val32 = in_le32(®->cer); if (val32) { u32 der; fsl_sata_dump_sfis((struct sfis *)cmd_desc->sfis); printf("CE at device\n\r"); fsl_sata_dump_regs(reg); der = in_le32(®->der); out_le32(®->cer, val32); out_le32(®->der, der); } /* Clear complete flags */ val32 = in_le32(®->ccr); out_le32(®->ccr, val32); return len;}static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct cfis *cfis, int tag, u8 *buffer, u32 len){ return 0;}static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis, enum cmd_type command_type, int tag, u8 *buffer, u32 len){ int rc; if (tag > SATA_HC_MAX_CMD || tag < 0) { printf("tag is out of range, tag=%d\n\r", tag); return -1; } switch (command_type) { case CMD_ATA: rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); return rc; case CMD_RESET: rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); return rc; case CMD_NCQ: rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); return rc; case CMD_ATAPI: case CMD_VENDOR_BIST: case CMD_BIST: printf("not support now\n\r"); return -1; default: break; } return -1;}static void fsl_sata_identify(int dev, u16 *id){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = ATA_CMD_ID_ATA; fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); ata_swap_buf_le16(id, ATA_ID_WORDS);}static void fsl_sata_xfer_mode(int dev, u16 *id){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; sata->pio = id[ATA_ID_PIO_MODES]; sata->mwdma = id[ATA_ID_MWDMA_MODES]; sata->udma = id[ATA_ID_UDMA_MODES]; debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma);}static void fsl_sata_set_features(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; u8 udma_cap; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = ATA_CMD_SET_FEATURES; cfis->features = SETFEATURES_XFER; /* First check the device capablity */ udma_cap = (u8)(sata->udma & 0xff); debug("udma_cap %02x\n\r", udma_cap); if (udma_cap == ATA_UDMA6) cfis->sector_count = XFER_UDMA_6; if (udma_cap == ATA_UDMA5) cfis->sector_count = XFER_UDMA_5; if (udma_cap == ATA_UDMA4) cfis->sector_count = XFER_UDMA_4; if (udma_cap == ATA_UDMA3) cfis->sector_count = XFER_UDMA_3; fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);}static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; u32 block; block = start; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; cfis->device = ATA_LBA; cfis->device |= (block >> 24) & 0xf; cfis->lba_high = (block >> 16) & 0xff; cfis->lba_mid = (block >> 8) & 0xff; cfis->lba_low = block & 0xff; cfis->sector_count = (u8)(blkcnt & 0xff); fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); return blkcnt;}void fsl_sata_flush_cache(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = ATA_CMD_FLUSH; fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);}static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; u64 block; block = (u64)start; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = (is_write) ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; cfis->lba_high_exp = (block >> 40) & 0xff; cfis->lba_mid_exp = (block >> 32) & 0xff; cfis->lba_low_exp = (block >> 24) & 0xff; cfis->lba_high = (block >> 16) & 0xff; cfis->lba_mid = (block >> 8) & 0xff; cfis->lba_low = block & 0xff; cfis->device = ATA_LBA; cfis->sector_count_exp = (blkcnt >> 8) & 0xff; cfis->sector_count = blkcnt & 0xff; fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); return blkcnt;}u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; int ncq_channel; u64 block; if (sata_dev_desc[dev].lba48 != 1) { printf("execute FPDMA command on non-LBA48 hard disk\n\r"); return -1; } block = (u64)start; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE : ATA_CMD_FPDMA_READ; cfis->lba_high_exp = (block >> 40) & 0xff; cfis->lba_mid_exp = (block >> 32) & 0xff; cfis->lba_low_exp = (block >> 24) & 0xff; cfis->lba_high = (block >> 16) & 0xff; cfis->lba_mid = (block >> 8) & 0xff; cfis->lba_low = block & 0xff; cfis->device = ATA_LBA; cfis->features_exp = (blkcnt >> 8) & 0xff; cfis->features = blkcnt & 0xff; if (sata->queue_depth >= SATA_HC_MAX_CMD) ncq_channel = SATA_HC_MAX_CMD - 1; else ncq_channel = sata->queue_depth - 1; /* Use the latest queue */ fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); return blkcnt;}void fsl_sata_flush_cache_ext(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d; struct cfis *cfis; cfis = (struct cfis *)&h2d; memset((void *)cfis, 0, sizeof(struct cfis)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ cfis->command = ATA_CMD_FLUSH_EXT; fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);}/* Software reset, set SRST of the Device Control register */void fsl_sata_software_reset(int dev){ return;}static void fsl_sata_init_wcache(int dev, u16 *id){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) sata->wcache = 1; if (ata_id_has_flush(id)) sata->flush = 1; if (ata_id_has_flush_ext(id)) sata->flush_ext = 1;}static int fsl_sata_get_wcache(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; return sata->wcache;}static int fsl_sata_get_flush(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; return sata->flush;}static int fsl_sata_get_flush_ext(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; return sata->flush_ext;}u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write){ u32 start, blks; u8 *addr; int max_blks; start = blknr; blks = blkcnt; addr = (u8 *)buffer; max_blks = ATA_MAX_SECTORS_LBA48; do { if (blks > max_blks) { if (fsl_sata_info[dev].flags != FLAGS_FPDMA) fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); else fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { if (fsl_sata_info[dev].flags != FLAGS_FPDMA) fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); else fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0); return blkcnt;}u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write){ u32 start, blks; u8 *addr; int max_blks; start = blknr; blks = blkcnt; addr = (u8 *)buffer; max_blks = ATA_MAX_SECTORS; do { if (blks > max_blks) { fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { fsl_sata_rw_cmd(dev, start, blks, addr, is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0); return blkcnt;}/* * SATA interface between low level driver and command layer */ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer){ u32 rc; if (sata_dev_desc[dev].lba48) rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); else rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); return rc;}ulong sata_write(int dev, u32 blknr, u32 blkcnt, void *buffer){ u32 rc; if (sata_dev_desc[dev].lba48) { rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) fsl_sata_flush_cache_ext(dev); } else { rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) fsl_sata_flush_cache(dev); } return rc;}int scan_sata(int dev){ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; unsigned char serial[ATA_ID_SERNO_LEN + 1]; unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; unsigned char product[ATA_ID_PROD_LEN + 1]; u16 *id; u64 n_sectors; /* if no detected link */ if (!sata->link) return -1; id = (u16 *)malloc(ATA_ID_WORDS * 2); if (!id) { printf("id malloc failed\n\r"); return -1; } /* Identify device to get information */ fsl_sata_identify(dev, id); /* Serial number */ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); /* Firmware version */ ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); /* Product model */ ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); /* Totoal sectors */ n_sectors = ata_id_n_sectors(id); sata_dev_desc[dev].lba = (u32)n_sectors; /* Check if support LBA48 */ if (ata_id_has_lba48(id)) { sata_dev_desc[dev].lba48 = 1; debug("Device support LBA48\n\r"); } /* Get the NCQ queue depth from device */ sata->queue_depth = ata_id_queue_depth(id); /* Get the xfer mode from device */ fsl_sata_xfer_mode(dev, id); /* Get the write cache status from device */ fsl_sata_init_wcache(dev, id); /* Set the xfer mode to highest speed */ fsl_sata_set_features(dev);#ifdef DEBUG fsl_sata_identify(dev, id); ata_dump_id(id);#endif free((void *)id); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -