From 2915a0223ae9632c9f555809ed20b3257ea47949 Mon Sep 17 00:00:00 2001 From: Richard Gibbs Date: Sat, 24 Aug 2013 10:10:47 -0500 Subject: ahci: use ports implemented map instead of num_ports The AHCI driver was incorrectly using the Capabilities register NP (number of ports) field to determine which ports to activate. This commit changes it to correctly use the PORTS_IMPL register as a port map. Signed-off-by: Richard Gibbs Reviewed-by: Tom Rini --- drivers/block/ahci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index e455ba5fb6..02ba02f427 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -119,6 +119,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) u32 tmp, cap_save, cmd; int i, j; volatile u8 *port_mmio; + u32 port_map; debug("ahci_host_init: start\n"); @@ -160,6 +161,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) #endif probe_ent->cap = readl(mmio + HOST_CAP); probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); + port_map = probe_ent->port_map; probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; debug("cap 0x%x port_map 0x%x n_ports %d\n", @@ -169,6 +171,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; for (i = 0; i < probe_ent->n_ports; i++) { + if (!(port_map & (1 << i))) + continue; probe_ent->port[i].port_mmio = ahci_port_base((u32) mmio, i); port_mmio = (u8 *) probe_ent->port[i].port_mmio; ahci_setup_port(&probe_ent->port[i], (unsigned long)mmio, i); -- cgit From 48c3a87c0a7026866c014fcc1a55281585fa5a41 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:48 -0500 Subject: ahci: fix unaligned access gcc 4.7 will generate unaligned accesses to local char arrays, so make them static to avoid that. Signed-off-by: Rob Herring Reviewed-by: Tom Rini --- drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 02ba02f427..f4d1d8174f 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -610,7 +610,7 @@ static void dump_ataid(hd_driveid_t *ataid) */ static int ata_scsiop_inquiry(ccb *pccb) { - u8 hdr[] = { + static const u8 hdr[] = { 0, 0, 0x5, /* claim SPC-3 version compatibility */ -- cgit From 796c2ebd6f17da605a05eb233c907e4d8330f751 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:49 -0500 Subject: ahci: fix memory leak in ata_scsiop_inquiry This fixes a memory leak when scsi inquiry fails. Signed-off-by: Rob Herring Reviewed-by: Tom Rini --- drivers/block/ahci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index f4d1d8174f..f08806348b 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -643,6 +643,7 @@ static int ata_scsiop_inquiry(ccb *pccb) if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), tmpid, sizeof(hd_driveid_t), 0)) { debug("scsi_ahci: SCSI inquiry command failure.\n"); + free(tmpid); return -EIO; } -- cgit From 2bdb10dbf59f41ead73fb3fa69699de1b621f423 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:50 -0500 Subject: ahci: add defines for PORT_SCR_STAT register bits Replace hard-coded register values with proper defines for PORT_SCR_STAT register. Signed-off-by: Rob Herring --- drivers/block/ahci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index f08806348b..ad7e95fe08 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -207,7 +207,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) j = 0; while (j < WAIT_MS_LINKUP) { tmp = readl(port_mmio + PORT_SCR_STAT); - if ((tmp & 0xf) == 0x3) + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) break; udelay(1000); j++; @@ -258,7 +259,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) /* register linkup ports */ tmp = readl(port_mmio + PORT_SCR_STAT); debug("SATA port %d status: 0x%x\n", i, tmp); - if ((tmp & 0xf) == 0x03) + if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) probe_ent->link_port_map |= (0x01 << i); } -- cgit From 124e9fa132338c32409bd556c9c0a47a2bb70cc2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:51 -0500 Subject: ahci: move link bring-up handling to separate function Move the link bring-up handling to a separate weak function in order to allow platforms to override it. This is needed on highbank platform which needs special phy handling. Signed-off-by: Rob Herring --- drivers/block/ahci.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index ad7e95fe08..5e7d01ba61 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -107,6 +107,27 @@ static int waiting_for_cmd_completed(volatile u8 *offset, return (i < timeout_msec) ? 0 : -1; } +int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) +{ + u32 tmp; + int j = 0; + u8 *port_mmio = (u8 *)probe_ent->port[port].port_mmio; + + /* + * Bring up SATA link. + * SATA link bringup time is usually less than 1 ms; only very + * rarely has it taken between 1-2 ms. Never seen it above 2 ms. + */ + while (j < WAIT_MS_LINKUP) { + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + return 0; + udelay(1000); + j++; + } + return 1; +} static int ahci_host_init(struct ahci_probe_ent *probe_ent) { @@ -117,7 +138,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) #endif volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base; u32 tmp, cap_save, cmd; - int i, j; + int i, j, ret; volatile u8 *port_mmio; u32 port_map; @@ -200,20 +221,9 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) cmd |= PORT_CMD_SPIN_UP; writel_with_flush(cmd, port_mmio + PORT_CMD); - /* Bring up SATA link. - * SATA link bringup time is usually less than 1 ms; only very - * rarely has it taken between 1-2 ms. Never seen it above 2 ms. - */ - j = 0; - while (j < WAIT_MS_LINKUP) { - tmp = readl(port_mmio + PORT_SCR_STAT); - tmp &= PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_PHYRDY) - break; - udelay(1000); - j++; - } - if (j == WAIT_MS_LINKUP) { + /* Bring up SATA link. */ + ret = ahci_link_up(probe_ent, i); + if (ret) { printf("SATA link %d timeout.\n", i); continue; } else { -- cgit From 178210847f7d8492c6aa1d39867d99538be0e7d4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:52 -0500 Subject: ahci: handle COMINIT received during spin-up Some Intel SSDs can send a COMINIT after the initial COMRESET. This causes the link to go down and we need to re-initialize the link. Signed-off-by: Rob Herring --- drivers/block/ahci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 5e7d01ba61..a7044f2ea7 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -243,8 +243,20 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) if (!(tmp & (ATA_STAT_BUSY | ATA_STAT_DRQ))) break; udelay(1000); + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + break; j++; } + + tmp = readl(port_mmio + PORT_SCR_STAT) & PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_COMINIT) { + debug("SATA link %d down (COMINIT received), retrying...\n", i); + i--; + continue; + } + printf("Target spinup took %d ms.\n", j); if (j == WAIT_MS_SPINUP) debug("timeout.\n"); -- cgit From 7610b41ddf3c8d1234b38817621f29407deaf32f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:53 -0500 Subject: ahci: increase spin-up timeout to 20 sec Based on Linux libata code, most drives are less than 10 sec, but some need up to 20 sec. Signed-off-by: Rob Herring Reviewed-by: Tom Rini --- drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index a7044f2ea7..7f78c00301 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -38,7 +38,7 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS]; #endif /* Maximum timeouts for each event */ -#define WAIT_MS_SPINUP 10000 +#define WAIT_MS_SPINUP 20000 #define WAIT_MS_DATAIO 5000 #define WAIT_MS_FLUSH 5000 #define WAIT_MS_LINKUP 4 -- cgit From 344ca0b40cf3a8feb1e7f9d4ff9e5041be706266 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 24 Aug 2013 10:10:54 -0500 Subject: ahci: convert to use libata functions and definitions libata already has similar functions as implemented in the ahci code. Refactor the code to use the libata variants and remove the dependency on ata.h. Convert some defines to use the version from libata.h. Also, remove some unnecessary memset's of bss data. This is a step toward hopefully merging ahci.c and dw_ahsata.c which are essentially the same driver. Signed-off-by: Rob Herring Reviewed-by: Tom Rini --- drivers/block/ahci.c | 80 ++++++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 56 deletions(-) (limited to 'drivers/block/ahci.c') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 7f78c00301..8cc9379b82 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -16,14 +16,14 @@ #include #include #include -#include +#include #include #include static int ata_io_flush(u8 port); struct ahci_probe_ent *probe_ent = NULL; -hd_driveid_t *ataid[AHCI_MAX_PORTS]; +u16 *ataid[AHCI_MAX_PORTS]; #define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) @@ -240,7 +240,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) j = 0; while (j < WAIT_MS_SPINUP) { tmp = readl(port_mmio + PORT_TFDATA); - if (!(tmp & (ATA_STAT_BUSY | ATA_STAT_DRQ))) + if (!(tmp & (ATA_BUSY | ATA_DRQ))) break; udelay(1000); tmp = readl(port_mmio + PORT_SCR_STAT); @@ -378,8 +378,6 @@ static int ahci_init_one(pci_dev_t pdev) u16 vendor; int rc; - memset((void *)ataid, 0, sizeof(hd_driveid_t *) * AHCI_MAX_PORTS); - probe_ent = malloc(sizeof(struct ahci_probe_ent)); memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); probe_ent->dev = pdev; @@ -469,7 +467,7 @@ static void ahci_set_feature(u8 port) memset(fis, 0, sizeof(fis)); fis[0] = 0x27; fis[1] = 1 << 7; - fis[2] = ATA_CMD_SETF; + fis[2] = ATA_CMD_SET_FEATURES; fis[3] = SETFEATURES_XFER; fis[12] = __ilog2(probe_ent->udma_mask + 1) + 0x40 - 0x01; @@ -607,27 +605,6 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len) 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. */ @@ -641,7 +618,7 @@ static int ata_scsiop_inquiry(ccb *pccb) 95 - 4, }; u8 fis[20]; - u8 *tmpid; + u16 *tmpid; u8 port; /* Clean ccb data buffer */ @@ -656,15 +633,16 @@ static int ata_scsiop_inquiry(ccb *pccb) /* Construct the FIS */ fis[0] = 0x27; /* Host to device FIS. */ fis[1] = 1 << 7; /* Command FIS. */ - fis[2] = ATA_CMD_IDENT; /* Command byte. */ + fis[2] = ATA_CMD_ID_ATA; /* Command byte. */ /* Read id from sata */ port = pccb->target; - if (!(tmpid = malloc(sizeof(hd_driveid_t)))) + tmpid = malloc(ATA_ID_WORDS * 2); + if (!tmpid) return -ENOMEM; - if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), tmpid, - sizeof(hd_driveid_t), 0)) { + if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, + ATA_ID_WORDS * 2, 0)) { debug("scsi_ahci: SCSI inquiry command failure.\n"); free(tmpid); return -EIO; @@ -672,13 +650,16 @@ static int ata_scsiop_inquiry(ccb *pccb) if (ataid[port]) free(ataid[port]); - ataid[port] = (hd_driveid_t *) tmpid; + ataid[port] = tmpid; + ata_swap_buf_le16(tmpid, ATA_ID_WORDS); 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); + ata_id_strcpy((u16 *) &pccb->pdata[16], &tmpid[ATA_ID_PROD], 16); + ata_id_strcpy((u16 *) &pccb->pdata[32], &tmpid[ATA_ID_FW_REV], 4); - dump_ataid(ataid[port]); +#ifdef DEBUG + ata_dump_id(tmpid); +#endif return 0; } @@ -726,7 +707,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write) now_blocks = min(MAX_SATA_BLOCKS_READ_WRITE, blocks); - transfer_size = ATA_BLOCKSIZE * now_blocks; + transfer_size = ATA_SECT_SIZE * now_blocks; if (transfer_size > user_buffer_size) { printf("scsi_ahci: Error: buffer too small.\n"); return -EIO; @@ -781,6 +762,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write) static int ata_scsiop_read_capacity10(ccb *pccb) { u32 cap; + u64 cap64; u32 block_size; if (!ataid[pccb->target]) { @@ -790,18 +772,11 @@ static int ata_scsiop_read_capacity10(ccb *pccb) return -EPERM; } - cap = le32_to_cpu(ataid[pccb->target]->lba_capacity); - if (cap == 0xfffffff) { - unsigned short *cap48 = ataid[pccb->target]->lba48_capacity; - if (cap48[2] || cap48[3]) { - cap = 0xffffffff; - } else { - cap = (le16_to_cpu(cap48[1]) << 16) | - (le16_to_cpu(cap48[0])); - } - } + cap64 = ata_id_n_sectors(ataid[pccb->target]); + if (cap64 > 0x100000000ULL) + cap64 = 0xffffffff; - cap = cpu_to_be32(cap); + cap = cpu_to_be32(cap64); memcpy(pccb->pdata, &cap, sizeof(cap)); block_size = cpu_to_be32((u32)512); @@ -826,12 +801,7 @@ static int ata_scsiop_read_capacity16(ccb *pccb) return -EPERM; } - cap = le32_to_cpu(ataid[pccb->target]->lba_capacity); - if (cap == 0xfffffff) { - memcpy(&cap, ataid[pccb->target]->lba48_capacity, sizeof(cap)); - cap = le64_to_cpu(cap); - } - + cap = ata_id_n_sectors(ataid[pccb->target]); cap = cpu_to_be64(cap); memcpy(pccb->pdata, &cap, sizeof(cap)); @@ -918,8 +888,6 @@ int ahci_init(u32 base) int i, rc = 0; u32 linkmap; - memset(ataid, 0, sizeof(ataid)); - probe_ent = malloc(sizeof(struct ahci_probe_ent)); memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); -- cgit