📄 ahci.c
字号:
fis[12] = __ilog2(probe_ent->udma_mask + 1) + 0x40 - 0x01; memcpy((unsigned char *)pp->cmd_tbl, fis, 20); ahci_fill_cmd_slot(pp, cmd_fis_len); writel(1, port_mmio + PORT_CMD_ISSUE); readl(port_mmio + PORT_CMD_ISSUE); if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) { printf("set feature error!\n"); }}static int ahci_port_start(u8 port){ struct ahci_ioports *pp = &(probe_ent->port[port]); volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio; u32 port_status; u32 mem; debug("Enter start port: %d\n", port); port_status = readl(port_mmio + PORT_SCR_STAT); debug("Port %d status: %x\n", port, port_status); if ((port_status & 0xf) != 0x03) { printf("No Link on this port!\n"); return -1; } mem = (u32) malloc(AHCI_PORT_PRIV_DMA_SZ + 2048); if (!mem) { free(pp); printf("No mem for table!\n"); return -ENOMEM; } mem = (mem + 0x800) & (~0x7ff); /* Aligned to 2048-bytes */ memset((u8 *) mem, 0, AHCI_PORT_PRIV_DMA_SZ); /* * First item in chunk of DMA memory: 32-slot command table, * 32 bytes each in size */ pp->cmd_slot = (struct ahci_cmd_hdr *)mem; debug("cmd_slot = 0x%x\n", pp->cmd_slot); mem += (AHCI_CMD_SLOT_SZ + 224); /* * Second item: Received-FIS area */ pp->rx_fis = mem; mem += AHCI_RX_FIS_SZ; /* * Third item: data area for storing a single command * and its scatter-gather table */ pp->cmd_tbl = mem; debug("cmd_tbl_dma = 0x%x\n", pp->cmd_tbl); mem += AHCI_CMD_TBL_HDR; pp->cmd_tbl_sg = (struct ahci_sg *)mem; writel_with_flush((u32) pp->cmd_slot, port_mmio + PORT_LST_ADDR); writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | PORT_CMD_START, port_mmio + PORT_CMD); debug("Exit start port %d\n", port); return 0;}static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf, int buf_len){ struct ahci_ioports *pp = &(probe_ent->port[port]); volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio; u32 opts; u32 port_status; int sg_count; debug("Enter get_ahci_device_data: for port %d\n", port); if (port > probe_ent->n_ports) { printf("Invaild port number %d\n", port); return -1; } port_status = readl(port_mmio + PORT_SCR_STAT); if ((port_status & 0xf) != 0x03) { debug("No Link on port %d!\n", port); return -1; } memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); sg_count = ahci_fill_sg(port, buf, buf_len); opts = (fis_len >> 2) | (sg_count << 16); ahci_fill_cmd_slot(pp, opts); writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) { printf("timeout exit!\n"); return -1; } debug("get_ahci_device_data: %d byte transferred.\n", pp->cmd_slot->status); return 0;}static char *ata_id_strcpy(u16 *target, u16 *src, int len){ int i; for (i = 0; i < len / 2; i++) target[i] = le16_to_cpu(src[i]); return (char *)target;}static void dump_ataid(hd_driveid_t *ataid){ debug("(49)ataid->capability = 0x%x\n", ataid->capability); debug("(53)ataid->field_valid =0x%x\n", ataid->field_valid); debug("(63)ataid->dma_mword = 0x%x\n", ataid->dma_mword); debug("(64)ataid->eide_pio_modes = 0x%x\n", ataid->eide_pio_modes); debug("(75)ataid->queue_depth = 0x%x\n", ataid->queue_depth); debug("(80)ataid->major_rev_num = 0x%x\n", ataid->major_rev_num); debug("(81)ataid->minor_rev_num = 0x%x\n", ataid->minor_rev_num); debug("(82)ataid->command_set_1 = 0x%x\n", ataid->command_set_1); debug("(83)ataid->command_set_2 = 0x%x\n", ataid->command_set_2); debug("(84)ataid->cfsse = 0x%x\n", ataid->cfsse); debug("(85)ataid->cfs_enable_1 = 0x%x\n", ataid->cfs_enable_1); debug("(86)ataid->cfs_enable_2 = 0x%x\n", ataid->cfs_enable_2); debug("(87)ataid->csf_default = 0x%x\n", ataid->csf_default); debug("(88)ataid->dma_ultra = 0x%x\n", ataid->dma_ultra); debug("(93)ataid->hw_config = 0x%x\n", ataid->hw_config);}/* * SCSI INQUIRY command operation. */static int ata_scsiop_inquiry(ccb *pccb){ u8 hdr[] = { 0, 0, 0x5, /* claim SPC-3 version compatibility */ 2, 95 - 4, }; u8 fis[20]; u8 *tmpid; u8 port; /* Clean ccb data buffer */ memset(pccb->pdata, 0, pccb->datalen); memcpy(pccb->pdata, hdr, sizeof(hdr)); if (pccb->datalen <= 35) return 0; memset(fis, 0, 20); /* Construct the FIS */ fis[0] = 0x27; /* Host to device FIS. */ fis[1] = 1 << 7; /* Command FIS. */ fis[2] = ATA_CMD_IDENT; /* Command byte. */ /* Read id from sata */ port = pccb->target; if (!(tmpid = malloc(sizeof(hd_driveid_t)))) return -ENOMEM; if (get_ahci_device_data(port, (u8 *) & fis, 20, tmpid, sizeof(hd_driveid_t))) { debug("scsi_ahci: SCSI inquiry command failure.\n"); return -EIO; } if (ataid[port]) free(ataid[port]); ataid[port] = (hd_driveid_t *) tmpid; memcpy(&pccb->pdata[8], "ATA ", 8); ata_id_strcpy((u16 *) &pccb->pdata[16], (u16 *)ataid[port]->model, 16); ata_id_strcpy((u16 *) &pccb->pdata[32], (u16 *)ataid[port]->fw_rev, 4); dump_ataid(ataid[port]); return 0;}/* * SCSI READ10 command operation. */static int ata_scsiop_read10(ccb * pccb){ u64 lba = 0; u32 len = 0; u8 fis[20]; lba = (((u64) pccb->cmd[2]) << 24) | (((u64) pccb->cmd[3]) << 16) | (((u64) pccb->cmd[4]) << 8) | ((u64) pccb->cmd[5]); len = (((u32) pccb->cmd[7]) << 8) | ((u32) pccb->cmd[8]); /* For 10-byte and 16-byte SCSI R/W commands, transfer * length 0 means transfer 0 block of data. * However, for ATA R/W commands, sector count 0 means * 256 or 65536 sectors, not 0 sectors as in SCSI. * * WARNING: one or two older ATA drives treat 0 as 0... */ if (!len) return 0; memset(fis, 0, 20); /* Construct the FIS */ fis[0] = 0x27; /* Host to device FIS. */ fis[1] = 1 << 7; /* Command FIS. */ fis[2] = ATA_CMD_RD_DMA; /* Command byte. */ /* LBA address, only support LBA28 in this driver */ fis[4] = pccb->cmd[5]; fis[5] = pccb->cmd[4]; fis[6] = pccb->cmd[3]; fis[7] = (pccb->cmd[2] & 0x0f) | 0xe0; /* Sector Count */ fis[12] = pccb->cmd[8]; fis[13] = pccb->cmd[7]; /* Read from ahci */ if (get_ahci_device_data(pccb->target, (u8 *) & fis, 20, pccb->pdata, pccb->datalen)) { debug("scsi_ahci: SCSI READ10 command failure.\n"); return -EIO; } return 0;}/* * SCSI READ CAPACITY10 command operation. */static int ata_scsiop_read_capacity10(ccb *pccb){ u8 buf[8]; if (!ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " "\tNo ATA info!\n" "\tPlease run SCSI commmand INQUIRY firstly!\n"); return -EPERM; } memset(buf, 0, 8); *(u32 *) buf = le32_to_cpu(ataid[pccb->target]->lba_capacity); buf[6] = 512 >> 8; buf[7] = 512 & 0xff; memcpy(pccb->pdata, buf, 8); return 0;}/* * SCSI TEST UNIT READY command operation. */static int ata_scsiop_test_unit_ready(ccb *pccb){ return (ataid[pccb->target]) ? 0 : -EPERM;}int scsi_exec(ccb *pccb){ int ret; switch (pccb->cmd[0]) { case SCSI_READ10: ret = ata_scsiop_read10(pccb); break; case SCSI_RD_CAPAC: ret = ata_scsiop_read_capacity10(pccb); break; case SCSI_TST_U_RDY: ret = ata_scsiop_test_unit_ready(pccb); break; case SCSI_INQUIRY: ret = ata_scsiop_inquiry(pccb); break; default: printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); return FALSE; } if (ret) { debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); return FALSE; } return TRUE;}void scsi_low_level_init(int busdevfunc){ int i; u32 linkmap; ahci_init_one(busdevfunc); linkmap = probe_ent->link_port_map; for (i = 0; i < CFG_SCSI_MAX_SCSI_ID; i++) { if (((linkmap >> i) & 0x01)) { if (ahci_port_start((u8) i)) { printf("Can not start port %d\n", i); continue; } ahci_set_feature((u8) i); } }}void scsi_bus_reset(void){ /*Not implement*/}void scsi_print_error(ccb * pccb){ /*The ahci error info can be read in the ahci driver*/}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -