diff options
Diffstat (limited to 'drivers/block')
| -rw-r--r-- | drivers/block/ahci.c | 142 | 
1 files changed, 69 insertions, 73 deletions
| diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index e455ba5fb..8cc9379b8 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -16,14 +16,14 @@  #include <asm/io.h>  #include <malloc.h>  #include <scsi.h> -#include <ata.h> +#include <libata.h>  #include <linux/ctype.h>  #include <ahci.h>  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) @@ -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 @@ -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,8 +138,9 @@ 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;  	debug("ahci_host_init: start\n"); @@ -160,6 +182,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 +192,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); @@ -196,19 +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); -			if ((tmp & 0xf) == 0x3) -				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 { @@ -225,11 +240,23 @@ 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); +			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"); @@ -254,7 +281,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);  	} @@ -351,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; @@ -442,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; @@ -580,33 +605,12 @@ 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.   */  static int ata_scsiop_inquiry(ccb *pccb)  { -	u8 hdr[] = { +	static const u8 hdr[] = {  		0,  		0,  		0x5,		/* claim SPC-3 version compatibility */ @@ -614,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 */ @@ -629,28 +633,33 @@ 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;  	}  	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;  } @@ -698,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; @@ -753,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]) { @@ -762,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); @@ -798,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)); @@ -890,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)); |