All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements
@ 2012-10-29 15:23 Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 01/22] ahci: Support splitting of read transactions into multiple chunks Simon Glass
                   ` (22 more replies)
  0 siblings, 23 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

This series contains a set of improvements for the SATA susbsystem, mostly
targeted at solid-state drivers and improving start-up time.

The patches are tested on various x86 Chromebooks.

Changes in v3:
- Remove use of DEFINE_PCI_DEVICE_TABLE suggested by siren checkpatch
- Use struct pci_device_id properly
- Add new patch to enable setenv_ulong/addr() for powerpc
- Fix setenv operation to use correct function
- Move missing #ifdef CONFIG_AHCI_SETFEATURES_XFER from later commit
- Remove . from end of commit subject
- Move #ifdef change into earlier commit
- Add patch to support 64-bit LBA option when reading capacity
- Add new patch to correct ide_read/write() function signatures

Changes in v2:
- Use struct pci_device_id instead of defining new struct scsi_device
- Squash in CONFIG_PCI patch
- Set 'scsidevs' environment variable to number of SCSI disks

Gabe Black (3):
  ahci: Make sending the SETFEATURES_XFER command optional
  ahci: Make the AHCI code find the capacity of disks > 128 GB properly
  ahci: Support 64-bit LBA option when reading capacity

Hung-Te Lin (2):
  scsi: Add scsi_write to SCSI driver
  ahci: support scsi writing in AHCI driver

Marc Jones (2):
  ahci: Support spin-up and link-up separately
  ahci: Perform SATA flush after disk write.

Simon Glass (3):
  Support setenv_ulong() and setenv_addr() for powerpc
  ide: Correct function signatures for ide_read/write()
  x86: config: Enable AHCI support for coreboot

Stefan Reinauer (4):
  scsi: Add function and env var to report number of scsi drives
  ahci: Optimise AHCI controller reset and start-up
  ahci: Improve AHCI debugging
  ahci: cosmetics and cleanup

Taylor Hutt (4):
  ahci: Use sizeof(fis) instead of hardcoding '20'
  ahci: Fix 'Invaild' typo
  ahci: Use virt_to_phys() to denote physical addresses for DMA
  ahci: flush / invalidate dcache around SATA commands

Vadim Bendebury (2):
  ahci: Support splitting of read transactions into multiple chunks
  scsi: Provide support for a list of AHCI controllers.

Walter Murphy (2):
  ahci: Adjust SATA timeouts for hard disk (spinup delay & command
    timeout)
  ahci: Expand HDD Logical Block addressability up to 32 bits

 README                     |    3 +
 common/cmd_ide.c           |   27 +--
 common/cmd_scsi.c          |  255 ++++++++++++++++++++++++----
 drivers/block/ahci.c       |  401 +++++++++++++++++++++++++++++++++++---------
 include/ahci.h             |    1 +
 include/ata.h              |    3 +
 include/common.h           |    2 +-
 include/configs/coreboot.h |   22 +++
 include/scsi.h             |    4 +
 9 files changed, 585 insertions(+), 133 deletions(-)

-- 
1.7.7.3

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 01/22] ahci: Support splitting of read transactions into multiple chunks
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 02/22] scsi: Provide support for a list of AHCI controllers Simon Glass
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Vadim Bendebury <vbendeb@chromium.org>

With an Intel AHCI controller, the driver does not operate properly
if the requested amount of blocks to read exceeds 255.

It is probably possible to specify 0 as the block count and the driver
will read 256 blocks, but it was decided to limit the number of blocks
read at once to 128 (it should be a power of 2 for the optimal
performance of solid state drives).

Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   98 +++++++++++++++++++++++++++++++++++---------------
 1 files changed, 69 insertions(+), 29 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 7b2ec50..d94da1f 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -42,6 +42,14 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];
 
 #define writel_with_flush(a,b)	do { writel(a,b); readl(b); } while (0)
 
+/*
+ * Some controllers limit number of blocks they can read at once. Contemporary
+ * SSD devices work much faster if the read size is aligned to a power of 2.
+ * Let's set default to 128 and allowing to be overwritten if needed.
+ */
+#ifndef MAX_SATA_BLOCKS_READ
+#define MAX_SATA_BLOCKS_READ	0x80
+#endif
 
 static inline u32 ahci_port_base(u32 base, u32 port)
 {
@@ -88,6 +96,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 	int i, j;
 	volatile u8 *port_mmio;
 
+	debug("ahci_host_init: start\n");
+
 	cap_save = readl(mmio + HOST_CAP);
 	cap_save &= ((1 << 28) | (1 << 17));
 	cap_save |= (1 << 27);
@@ -129,6 +139,9 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 	debug("cap 0x%x  port_map 0x%x  n_ports %d\n",
 	      probe_ent->cap, probe_ent->port_map, probe_ent->n_ports);
 
+	if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
+		probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
+
 	for (i = 0; i < probe_ent->n_ports; i++) {
 		probe_ent->port[i].port_mmio = ahci_port_base((u32) mmio, i);
 		port_mmio = (u8 *) probe_ent->port[i].port_mmio;
@@ -277,8 +290,8 @@ static int ahci_init_one(pci_dev_t pdev)
 	probe_ent->pio_mask = 0x1f;
 	probe_ent->udma_mask = 0x7f;	/*Fixme,assume to support UDMA6 */
 
-	probe_ent->mmio_base = (u32)pci_map_bar(pdev, AHCI_PCI_BAR,
-						PCI_REGION_MEM);
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &probe_ent->mmio_base);
+	debug("ahci mmio_base=0x%08x\n", probe_ent->mmio_base);
 
 	/* Take from kernel:
 	 * JMicron-specific fixup:
@@ -398,7 +411,7 @@ static int ahci_port_start(u8 port)
 	 * 32 bytes each in size
 	 */
 	pp->cmd_slot = (struct ahci_cmd_hdr *)mem;
-	debug("cmd_slot = %p\n", pp->cmd_slot);
+	debug("cmd_slot = 0x%x\n", (unsigned)pp->cmd_slot);
 	mem += (AHCI_CMD_SLOT_SZ + 224);
 
 	/*
@@ -561,42 +574,69 @@ static int ata_scsiop_inquiry(ccb *pccb)
  */
 static int ata_scsiop_read10(ccb * pccb)
 {
-	u32 len = 0;
+	u32 lba = 0;
+	u16 blocks = 0;
 	u8 fis[20];
+	u8 *user_buffer = pccb->pdata;
+	u32 user_buffer_size = pccb->datalen;
 
-	len = (((u32) pccb->cmd[7]) << 8) | ((u32) pccb->cmd[8]);
+	/* Retrieve the base LBA number from the ccb structure. */
+	memcpy(&lba, pccb->cmd + 2, sizeof(lba));
+	lba = be32_to_cpu(lba);
 
-	/* For 10-byte and 16-byte SCSI R/W commands, transfer
+	/*
+	 * And the number of blocks.
+	 *
+	 * 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;
+	blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]);
+
+	debug("scsi_ahci: read %d blocks starting from lba 0x%x\n",
+	      (unsigned)lba, blocks);
+
+	/* Preset the FIS */
 	memset(fis, 0, 20);
+	fis[0] = 0x27;		 /* Host to device FIS. */
+	fis[1] = 1 << 7;	 /* Command FIS. */
+	fis[2] = ATA_CMD_RD_DMA; /* Command byte. */
 
-	/* 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;
+	while (blocks) {
+		u16 now_blocks; /* number of blocks per iteration */
+		u32 transfer_size; /* number of bytes per iteration */
+
+		now_blocks = min(MAX_SATA_BLOCKS_READ, blocks);
+
+		transfer_size = ATA_BLOCKSIZE * now_blocks;
+		if (transfer_size > user_buffer_size) {
+			printf("scsi_ahci: Error: buffer too small.\n");
+			return -EIO;
+		}
+
+		/* LBA address, only support LBA28 in this driver */
+		fis[4] = (lba >> 0) & 0xff;
+		fis[5] = (lba >> 8) & 0xff;
+		fis[6] = (lba >> 16) & 0xff;
+		fis[7] = ((lba >> 24) & 0xf) | 0xe0;
+
+		/* Block (sector) count */
+		fis[12] = (now_blocks >> 0) & 0xff;
+		fis[13] = (now_blocks >> 8) & 0xff;
+
+		/* Read from ahci */
+		if (get_ahci_device_data(pccb->target, (u8 *) &fis, sizeof(fis),
+					 user_buffer, user_buffer_size)) {
+			debug("scsi_ahci: SCSI READ10 command failure.\n");
+			return -EIO;
+		}
+		user_buffer += transfer_size;
+		user_buffer_size -= transfer_size;
+		blocks -= now_blocks;
+		lba += now_blocks;
 	}
 
 	return 0;
@@ -617,7 +657,7 @@ static int ata_scsiop_read_capacity10(ccb *pccb)
 		return -EPERM;
 	}
 
-	cap = le32_to_cpu(ataid[pccb->target]->lba_capacity);
+	cap = be32_to_cpu(ataid[pccb->target]->lba_capacity);
 	memcpy(pccb->pdata, &cap, sizeof(cap));
 
 	pccb->pdata[4] = pccb->pdata[5] = 0;
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 02/22] scsi: Provide support for a list of AHCI controllers.
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 01/22] ahci: Support splitting of read transactions into multiple chunks Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 03/22] scsi: Add scsi_write to SCSI driver Simon Glass
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Vadim Bendebury <vbendeb@chromium.org>

Many AHCI controllers are identical, the main (and often the
only) difference being the PCI Vendor ID/Device ID combination
reported by the device.

This change allows the config file to define a list of PCI vendor
ID/device ID pairs. The driver would scan the list and initialize
the first device it finds.

No actual multiple device list is introduced yet, this change
just add the framework.

Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Remove use of DEFINE_PCI_DEVICE_TABLE suggested by siren checkpatch
- Use struct pci_device_id properly

Changes in v2:
- Use struct pci_device_id instead of defining new struct scsi_device
- Squash in CONFIG_PCI patch

 common/cmd_scsi.c |   40 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c
index 22d0119..50eb239 100644
--- a/common/cmd_scsi.c
+++ b/common/cmd_scsi.c
@@ -34,6 +34,9 @@
 #include <image.h>
 #include <pci.h>
 
+#ifdef CONFIG_SCSI_DEV_LIST
+#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
+#else
 #ifdef CONFIG_SCSI_SYM53C8XX
 #define SCSI_VEND_ID	0x1000
 #ifndef CONFIG_SCSI_DEV_ID
@@ -49,8 +52,12 @@
 #elif !defined(CONFIG_SCSI_AHCI_PLAT)
 #error no scsi device defined
 #endif
+#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
+#endif
 
-
+#ifdef CONFIG_PCI
+const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
+#endif
 static ccb tempccb;	/* temporary scsi command buffer */
 
 static unsigned char tempbuff[512]; /* temporary data buffer */
@@ -178,15 +185,38 @@ removable:
 void scsi_init(void)
 {
 	int busdevfunc;
+	int i;
+	/*
+	 * Find a device from the list, this driver will support a single
+	 * controller.
+	 */
+	for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
+		/* get PCI Device ID */
+		busdevfunc = pci_find_device(scsi_device_list[i].vendor,
+					     scsi_device_list[i].device,
+					     0);
+		if (busdevfunc != -1)
+			break;
+	}
 
-	busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */
-	if(busdevfunc==-1) {
-		printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID);
+	if (busdevfunc == -1) {
+		printf("Error: SCSI Controller(s) ");
+		for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
+			printf("%04X:%04X ",
+			       scsi_device_list[i].vendor,
+			       scsi_device_list[i].device);
+		}
+		printf("not found\n");
 		return;
 	}
 #ifdef DEBUG
 	else {
-		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7);
+		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
+		       scsi_device_list[i].vendor,
+		       scsi_device_list[i].device,
+		       (busdevfunc >> 16) & 0xFF,
+		       (busdevfunc >> 11) & 0x1F,
+		       (busdevfunc >> 8) & 0x7);
 	}
 #endif
 	scsi_low_level_init(busdevfunc);
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 03/22] scsi: Add scsi_write to SCSI driver
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 01/22] ahci: Support splitting of read transactions into multiple chunks Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 02/22] scsi: Provide support for a list of AHCI controllers Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 04/22] Support setenv_ulong() and setenv_addr() for powerpc Simon Glass
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Hung-Te Lin <hungte@chromium.org>

Implement write functionality in the scsi layer. A ''scsi write'
command is also added to console for testing.

Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/cmd_scsi.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c
index 50eb239..31ea788 100644
--- a/common/cmd_scsi.c
+++ b/common/cmd_scsi.c
@@ -75,11 +75,15 @@ void scsi_setup_test_unit_ready(ccb * pccb);
 void scsi_setup_read_capacity(ccb * pccb);
 void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);
 void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);
+static void scsi_setup_write_ext(ccb *pccb, unsigned long start,
+			  unsigned short blocks);
 void scsi_setup_inquiry(ccb * pccb);
 void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
 
 
-ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer);
+static ulong scsi_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer);
+static ulong scsi_write(int device, ulong blknr,
+			lbaint_t blkcnt, const void *buffer);
 
 
 /*********************************************************************************
@@ -109,6 +113,7 @@ void scsi_scan(int mode)
 		scsi_dev_desc[i].dev=i;
 		scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
 		scsi_dev_desc[i].block_read=scsi_read;
+		scsi_dev_desc[i].block_write = scsi_write;
 	}
 	scsi_max_devs=0;
 	for(i=0;i<CONFIG_SYS_SCSI_MAX_SCSI_ID;i++) {
@@ -335,6 +340,19 @@ int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 				n = scsi_read(scsi_curr_dev, blk, cnt, (ulong *)addr);
 				printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR");
 				return 0;
+			} else if (strcmp(argv[1], "write") == 0) {
+				ulong addr = simple_strtoul(argv[2], NULL, 16);
+				ulong blk = simple_strtoul(argv[3], NULL, 16);
+				ulong cnt = simple_strtoul(argv[4], NULL, 16);
+				ulong n;
+				printf("\nSCSI write: device %d block # %ld, "
+				       "count %ld ... ",
+				       scsi_curr_dev, blk, cnt);
+				n = scsi_write(scsi_curr_dev, blk, cnt,
+					       (ulong *)addr);
+				printf("%ld blocks written: %s\n", n,
+				       (n == cnt) ? "OK" : "ERROR");
+				return 0;
 			}
 	} /* switch */
 	return CMD_RET_USAGE;
@@ -346,9 +364,10 @@ int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */
 
-ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer)
+static ulong scsi_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
 {
-	ulong start,blks, buf_addr;
+	lbaint_t start, blks;
+	uintptr_t buf_addr;
 	unsigned short smallblks;
 	ccb* pccb=(ccb *)&tempccb;
 	device&=0xff;
@@ -359,7 +378,9 @@ ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer)
 	buf_addr=(unsigned long)buffer;
 	start=blknr;
 	blks=blkcnt;
-	debug ("\nscsi_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks,(unsigned long)buffer);
+	debug("\nscsi_read: dev %d startblk " LBAF
+	      ", blccnt " LBAF " buffer %lx\n",
+	      device, start, blks, (unsigned long)buffer);
 	do {
 		pccb->pdata=(unsigned char *)buf_addr;
 		if(blks>SCSI_MAX_READ_BLK) {
@@ -376,7 +397,9 @@ ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer)
 			start+=blks;
 			blks=0;
 		}
-		debug ("scsi_read_ext: startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+		debug("scsi_read_ext: startblk " LBAF
+		      ", blccnt %x buffer %lx\n",
+		      start, smallblks, buf_addr);
 		if(scsi_exec(pccb)!=TRUE) {
 			scsi_print_error(pccb);
 			blkcnt-=blks;
@@ -384,10 +407,65 @@ ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer)
 		}
 		buf_addr+=pccb->datalen;
 	} while(blks!=0);
-	debug ("scsi_read_ext: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+	debug("scsi_read_ext: end startblk " LBAF
+	      ", blccnt %x buffer %lx\n", start, smallblks, buf_addr);
 	return(blkcnt);
 }
 
+/*******************************************************************************
+ * scsi_write
+ */
+
+/* Almost the maximum amount of the scsi_ext command.. */
+#define SCSI_MAX_WRITE_BLK 0xFFFF
+
+static ulong scsi_write(int device, ulong blknr,
+			lbaint_t blkcnt, const void *buffer)
+{
+	lbaint_t start, blks;
+	uintptr_t buf_addr;
+	unsigned short smallblks;
+	ccb* pccb = (ccb *)&tempccb;
+	device &= 0xff;
+	/* Setup  device
+	 */
+	pccb->target = scsi_dev_desc[device].target;
+	pccb->lun = scsi_dev_desc[device].lun;
+	buf_addr = (unsigned long)buffer;
+	start = blknr;
+	blks = blkcnt;
+	debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+	      __func__, device, start, blks, (unsigned long)buffer);
+	do {
+		pccb->pdata = (unsigned char *)buf_addr;
+		if (blks > SCSI_MAX_WRITE_BLK) {
+			pccb->datalen = (scsi_dev_desc[device].blksz *
+					 SCSI_MAX_WRITE_BLK);
+			smallblks = SCSI_MAX_WRITE_BLK;
+			scsi_setup_write_ext(pccb, start, smallblks);
+			start += SCSI_MAX_WRITE_BLK;
+			blks -= SCSI_MAX_WRITE_BLK;
+		} else {
+			pccb->datalen = scsi_dev_desc[device].blksz * blks;
+			smallblks = (unsigned short)blks;
+			scsi_setup_write_ext(pccb, start, smallblks);
+			start += blks;
+			blks = 0;
+		}
+		debug("%s: startblk " LBAF ", blccnt %x buffer %lx\n",
+		      __func__, start, smallblks, buf_addr);
+		if (scsi_exec(pccb) != TRUE) {
+			scsi_print_error(pccb);
+			blkcnt -= blks;
+			break;
+		}
+		buf_addr += pccb->datalen;
+	} while (blks != 0);
+	debug("%s: end startblk " LBAF ", blccnt %x buffer %lx\n",
+	      __func__, start, smallblks, buf_addr);
+	return blkcnt;
+}
+
 /* copy src to dest, skipping leading and trailing blanks
  * and null terminate the string
  */
@@ -481,6 +559,27 @@ void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks)
 		pccb->cmd[7],pccb->cmd[8]);
 }
 
+void scsi_setup_write_ext(ccb *pccb, unsigned long start, unsigned short blocks)
+{
+	pccb->cmd[0] = SCSI_WRITE10;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = ((unsigned char) (start>>24)) & 0xff;
+	pccb->cmd[3] = ((unsigned char) (start>>16)) & 0xff;
+	pccb->cmd[4] = ((unsigned char) (start>>8)) & 0xff;
+	pccb->cmd[5] = ((unsigned char) (start)) & 0xff;
+	pccb->cmd[6] = 0;
+	pccb->cmd[7] = ((unsigned char) (blocks>>8)) & 0xff;
+	pccb->cmd[8] = (unsigned char)blocks & 0xff;
+	pccb->cmd[9] = 0;
+	pccb->cmdlen = 10;
+	pccb->msgout[0] = SCSI_IDENTIFY;  /* NOT USED */
+	debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
+	      __func__,
+	      pccb->cmd[0], pccb->cmd[1],
+	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
+	      pccb->cmd[7], pccb->cmd[8]);
+}
+
 void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks)
 {
 	pccb->cmd[0]=SCSI_READ6;
@@ -522,7 +621,9 @@ U_BOOT_CMD(
 	"scsi device [dev] - show or set current device\n"
 	"scsi part [dev] - print partition table of one or all SCSI devices\n"
 	"scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
-	"     to memory address `addr'"
+	"     to memory address `addr'\n"
+	"scsi write addr blk# cnt - write `cnt' blocks starting at block\n"
+	"     `blk#' from memory address `addr'"
 );
 
 U_BOOT_CMD(
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 04/22] Support setenv_ulong() and setenv_addr() for powerpc
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (2 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 03/22] scsi: Add scsi_write to SCSI driver Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 05/22] scsi: Add function and env var to report number of scsi drives Simon Glass
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

This includes were outside an #ifdef CONFIG_PPC, but there is not reason
to exclude powerpc from using them.

Move the declaration outside the #ifdef.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Add new patch to enable setenv_ulong/addr() for powerpc

 include/common.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/common.h b/include/common.h
index b23e90b..12b3e03 100644
--- a/include/common.h
+++ b/include/common.h
@@ -345,9 +345,9 @@ int	saveenv	     (void);
 int inline setenv    (const char *, const char *);
 #else
 int	setenv	     (const char *, const char *);
+#endif /* CONFIG_PPC */
 int setenv_ulong(const char *varname, ulong value);
 int setenv_addr(const char *varname, const void *addr);
-#endif /* CONFIG_PPC */
 #ifdef CONFIG_ARM
 # include <asm/mach-types.h>
 # include <asm/setup.h>
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 05/22] scsi: Add function and env var to report number of scsi drives
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (3 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 04/22] Support setenv_ulong() and setenv_addr() for powerpc Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 06/22] ahci: Optimise AHCI controller reset and start-up Simon Glass
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Stefan Reinauer <reinauer@chromium.org>

Add a new function to find out the number of available SCSI disks. Also
set the 'scsidevs' environment variable after each scan.

Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Fix setenv operation to use correct function

Changes in v2:
- Set 'scsidevs' environment variable to number of SCSI disks

 README            |    3 +++
 common/cmd_scsi.c |    8 ++++++++
 include/scsi.h    |    2 ++
 3 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/README b/README
index 69da2b8..801772c 100644
--- a/README
+++ b/README
@@ -1039,6 +1039,9 @@ The following options need to be configured:
 		devices.
 		CONFIG_SYS_SCSI_SYM53C8XX_CCF to fix clock timing (80Mhz)
 
+                The environment variable 'scsidevs' is set to the number of
+                SCSI devices found during the last scan.
+
 - NETWORK Support (PCI):
 		CONFIG_E1000
 		Support for Intel 8254x/8257x gigabit chips.
diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c
index 31ea788..9bd8ec9 100644
--- a/common/cmd_scsi.c
+++ b/common/cmd_scsi.c
@@ -184,6 +184,14 @@ removable:
 		scsi_curr_dev=0;
 	else
 		scsi_curr_dev = -1;
+
+	printf("Found %d device(s).\n", scsi_max_devs);
+	setenv_ulong("scsidevs", scsi_max_devs);
+}
+
+int scsi_get_disk_count(void)
+{
+	return scsi_max_devs;
 }
 
 #ifdef CONFIG_PCI
diff --git a/include/scsi.h b/include/scsi.h
index 89ae45f..9681d19 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -189,6 +189,8 @@ void scsi_low_level_init(int busdevfunc);
 void scsi_init(void);
 void scsi_scan(int mode);
 
+/** @return the number of scsi disks */
+int scsi_get_disk_count(void);
 
 #define SCSI_IDENTIFY					0xC0  /* not used */
 
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 06/22] ahci: Optimise AHCI controller reset and start-up
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (4 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 05/22] scsi: Add function and env var to report number of scsi drives Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 07/22] ahci: Improve AHCI debugging Simon Glass
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Stefan Reinauer <reinauer@chromium.org>

The existing code waits a whole second for the AHCI controller to reset.
Instead, let's poll the status register to see if the reset has
succeeded and return earlier if possible. This brings down the time for
AHCI probing from 1s to 20ms.

Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   24 +++++++++++++++---------
 1 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index d94da1f..ad397dc 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -110,13 +110,15 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 	/* reset must complete within 1 second, or
 	 * the hardware should be considered fried.
 	 */
-	ssleep(1);
-
-	tmp = readl(mmio + HOST_CTL);
-	if (tmp & HOST_RESET) {
-		debug("controller reset failed (0x%x)\n", tmp);
-		return -1;
-	}
+	i = 1000;
+	do {
+		udelay(1000);
+		tmp = readl(mmio + HOST_CTL);
+		if (!i--) {
+			debug("controller reset failed (0x%x)\n", tmp);
+			return -1;
+		}
+	} while (tmp & HOST_RESET);
 
 	writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL);
 	writel(cap_save, mmio + HOST_CAP);
@@ -164,13 +166,17 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 		writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
 
 		j = 0;
-		while (j < 100) {
-			msleep(10);
+		while (j < 1000) {
 			tmp = readl(port_mmio + PORT_SCR_STAT);
 			if ((tmp & 0xf) == 0x3)
 				break;
+			udelay(1000);
 			j++;
 		}
+		if (j == 1000)
+			debug("timeout.\n");
+		else
+			debug("ok.\n");
 
 		tmp = readl(port_mmio + PORT_SCR_ERR);
 		debug("PORT_SCR_ERR 0x%x\n", tmp);
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 07/22] ahci: Improve AHCI debugging
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (5 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 06/22] ahci: Optimise AHCI controller reset and start-up Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 08/22] ahci: cosmetics and cleanup Simon Glass
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Stefan Reinauer <reinauer@chromium.org>

- remove unused ssleep macro
- add some useful debugging information

Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index ad397dc..af31c97 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -68,7 +68,6 @@ static void ahci_setup_port(struct ahci_ioports *port, unsigned long base,
 
 
 #define msleep(a) udelay(a * 1000)
-#define ssleep(a) msleep(a * 1000)
 
 static int waiting_for_cmd_completed(volatile u8 *offset,
 				     int timeout_msec,
@@ -153,6 +152,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 		tmp = readl(port_mmio + PORT_CMD);
 		if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
 			   PORT_CMD_FIS_RX | PORT_CMD_START)) {
+			debug("Port %d is active. Deactivating.\n", i);
 			tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
 				 PORT_CMD_FIS_RX | PORT_CMD_START);
 			writel_with_flush(tmp, port_mmio + PORT_CMD);
@@ -163,6 +163,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 			msleep(500);
 		}
 
+		debug("Spinning up port %d... ", i);
 		writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
 
 		j = 0;
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 08/22] ahci: cosmetics and cleanup
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (6 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 07/22] ahci: Improve AHCI debugging Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 09/22] ahci: Make sending the SETFEATURES_XFER command optional Simon Glass
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Stefan Reinauer <reinauer@chromium.org>

- print the correct speed
- print all the AHCI capability flags
(information taken from Linux kernel driver)
- clean up some comments

For example, this might show the following string:
AHCI 0001.0300 32 slots 6 ports 6 Gbps 0x3 impl SATA mode

Signed-off-by: Stefan Reinauer <reinauer@chromium.org>

Commit-Ready: Stefan Reinauer <reinauer@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Tested-by: Stefan Reinauer <reinauer@chromium.org>
---

 drivers/block/ahci.c |   25 ++++++++++++++++++-------
 include/ahci.h       |    1 +
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index af31c97..0a7ad81 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -194,7 +194,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 		/* set irq mask (enables interrupts) */
 		writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
 
-		/*register linkup ports */
+		/* register linkup ports */
 		tmp = readl(port_mmio + PORT_SCR_STAT);
 		debug("Port %d status: 0x%x\n", i, tmp);
 		if ((tmp & 0xf) == 0x03)
@@ -222,12 +222,13 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
 	u16 cc;
 #endif
 	volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;
-	u32 vers, cap, impl, speed;
+	u32 vers, cap, cap2, impl, speed;
 	const char *speed_s;
 	const char *scc_s;
 
 	vers = readl(mmio + HOST_VERSION);
 	cap = probe_ent->cap;
+	cap2 = readl(mmio + HOST_CAP2);
 	impl = probe_ent->port_map;
 
 	speed = (cap >> 20) & 0xf;
@@ -235,6 +236,8 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
 		speed_s = "1.5";
 	else if (speed == 2)
 		speed_s = "3";
+	else if (speed == 3)
+		speed_s = "6";
 	else
 		speed_s = "?";
 
@@ -260,8 +263,9 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
 	       ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s);
 
 	printf("flags: "
-	       "%s%s%s%s%s%s"
-	       "%s%s%s%s%s%s%s\n",
+	       "%s%s%s%s%s%s%s"
+	       "%s%s%s%s%s%s%s"
+	       "%s%s%s%s%s%s\n",
 	       cap & (1 << 31) ? "64bit " : "",
 	       cap & (1 << 30) ? "ncq " : "",
 	       cap & (1 << 28) ? "ilck " : "",
@@ -272,9 +276,16 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
 	       cap & (1 << 19) ? "nz " : "",
 	       cap & (1 << 18) ? "only " : "",
 	       cap & (1 << 17) ? "pmp " : "",
+	       cap & (1 << 16) ? "fbss " : "",
 	       cap & (1 << 15) ? "pio " : "",
 	       cap & (1 << 14) ? "slum " : "",
-	       cap & (1 << 13) ? "part " : "");
+	       cap & (1 << 13) ? "part " : "",
+	       cap & (1 << 7) ? "ccc " : "",
+	       cap & (1 << 6) ? "ems " : "",
+	       cap & (1 << 5) ? "sxs " : "",
+	       cap2 & (1 << 2) ? "apst " : "",
+	       cap2 & (1 << 1) ? "nvmp " : "",
+	       cap2 & (1 << 0) ? "boh " : "");
 }
 
 #ifndef CONFIG_SCSI_AHCI_PLAT
@@ -369,7 +380,7 @@ static void ahci_set_feature(u8 port)
 	u32 cmd_fis_len = 5;	/* five dwords */
 	u8 fis[20];
 
-	/*set feature */
+	/* set feature */
 	memset(fis, 0, 20);
 	fis[0] = 0x27;
 	fis[1] = 1 << 7;
@@ -383,7 +394,7 @@ static void ahci_set_feature(u8 port)
 	readl(port_mmio + PORT_CMD_ISSUE);
 
 	if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) {
-		printf("set feature error!\n");
+		printf("set feature error on port %d!\n", port);
 	}
 }
 
diff --git a/include/ahci.h b/include/ahci.h
index c4fb9e7..babbdc6 100644
--- a/include/ahci.h
+++ b/include/ahci.h
@@ -51,6 +51,7 @@
 #define HOST_IRQ_STAT		0x08 /* interrupt status */
 #define HOST_PORTS_IMPL		0x0c /* bitmap of implemented ports */
 #define HOST_VERSION		0x10 /* AHCI spec. version compliancy */
+#define HOST_CAP2		0x24 /* host capabilities, extended */
 
 /* HOST_CTL bits */
 #define HOST_RESET		(1 << 0)  /* reset controller; self-clear */
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 09/22] ahci: Make sending the SETFEATURES_XFER command optional
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (7 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 08/22] ahci: cosmetics and cleanup Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 10/22] ahci: support scsi writing in AHCI driver Simon Glass
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Gabe Black <gabeblack@chromium.org>

This command doesn't really do anything when talking to a SATA device, and
sending it confuses some of them. This change makes sending the command
optional, and defaults to not. The situations where it should be sent are not
the common case.

With the standard SSD in the machine, here are some times with the option
turned off:
1. 8277
2. 8273
3. 8050

And turned on:
1. 8303
2. 8155
3. 8276

Sending that command seems to have no meaningful effect on performance.

This fixes problems with an SSD marked Toshiba NV6424, Taiwan 11159AE P
and TC58NVG5D2FTA10.

Signed-off-by: Gabe Black <gabeblack@chromium.org>
Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Move missing #ifdef CONFIG_AHCI_SETFEATURES_XFER from later commit

 drivers/block/ahci.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 0a7ad81..2236321 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -373,6 +373,7 @@ static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts)
 }
 
 
+#ifdef CONFIG_AHCI_SETFEATURES_XFER
 static void ahci_set_feature(u8 port)
 {
 	struct ahci_ioports *pp = &(probe_ent->port[port]);
@@ -397,6 +398,7 @@ static void ahci_set_feature(u8 port)
 		printf("set feature error on port %d!\n", port);
 	}
 }
+#endif
 
 
 static int ahci_port_start(u8 port)
@@ -743,7 +745,9 @@ void scsi_low_level_init(int busdevfunc)
 				printf("Can not start port %d\n", i);
 				continue;
 			}
+#ifdef CONFIG_AHCI_SETFEATURES_XFER
 			ahci_set_feature((u8) i);
+#endif
 		}
 	}
 }
@@ -784,7 +788,9 @@ int ahci_init(u32 base)
 				printf("Can not start port %d\n", i);
 				continue;
 			}
+#ifdef CONFIG_AHCI_SETFEATURES_XFER
 			ahci_set_feature((u8) i);
+#endif
 		}
 	}
 err_out:
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 10/22] ahci: support scsi writing in AHCI driver
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (8 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 09/22] ahci: Make sending the SETFEATURES_XFER command optional Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 11/22] ahci: Make the AHCI code find the capacity of disks > 128 GB properly Simon Glass
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Hung-Te Lin <hungte@chromium.org>

The "scsi write" command requires support from underlying driver.
This CL enables SCSI_WRITE10 in AHCI driver.

Tested in U-Boot console, try to i/o with sector #64:
scsi read 1000 40 1
md.b 1000 200 # check if things are not 0xcc
mw.b 1000 cc 200 # try to fill with 0xcc
scsi write 1000 40 1
mw.b 1000 0 200 # fill with zero
md.b 1000 200 # should be all 0
scsi read 1000 40 1
md.b 1000 200 # should be all 0xcc

Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Remove . from end of commit subject

 drivers/block/ahci.c |   54 +++++++++++++++++++++++++++----------------------
 1 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 2236321..5092352 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -43,12 +43,13 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];
 #define writel_with_flush(a,b)	do { writel(a,b); readl(b); } while (0)
 
 /*
- * Some controllers limit number of blocks they can read at once. Contemporary
- * SSD devices work much faster if the read size is aligned to a power of 2.
- * Let's set default to 128 and allowing to be overwritten if needed.
+ * Some controllers limit number of blocks they can read/write at once.
+ * Contemporary SSD devices work much faster if the read/write size is aligned
+ * to a power of 2.  Let's set default to 128 and allowing to be overwritten if
+ * needed.
  */
-#ifndef MAX_SATA_BLOCKS_READ
-#define MAX_SATA_BLOCKS_READ	0x80
+#ifndef MAX_SATA_BLOCKS_READ_WRITE
+#define MAX_SATA_BLOCKS_READ_WRITE	0x80
 #endif
 
 static inline u32 ahci_port_base(u32 base, u32 port)
@@ -464,8 +465,8 @@ static int ahci_port_start(u8 port)
 }
 
 
-static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf,
-				int buf_len)
+static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
+				int buf_len, u8 is_write)
 {
 
 	struct ahci_ioports *pp = &(probe_ent->port[port]);
@@ -474,7 +475,7 @@ static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf,
 	u32 port_status;
 	int sg_count;
 
-	debug("Enter get_ahci_device_data: for port %d\n", port);
+	debug("Enter %s: for port %d\n", __func__, port);
 
 	if (port > probe_ent->n_ports) {
 		printf("Invaild port number %d\n", port);
@@ -490,7 +491,7 @@ static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf,
 	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);
+	opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6);
 	ahci_fill_cmd_slot(pp, opts);
 
 	writel_with_flush(1, port_mmio + PORT_CMD_ISSUE);
@@ -499,8 +500,7 @@ static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf,
 		printf("timeout exit!\n");
 		return -1;
 	}
-	debug("get_ahci_device_data: %d byte transferred.\n",
-	      pp->cmd_slot->status);
+	debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status);
 
 	return 0;
 }
@@ -570,8 +570,8 @@ static int ata_scsiop_inquiry(ccb *pccb)
 	if (!(tmpid = malloc(sizeof(hd_driveid_t))))
 		return -ENOMEM;
 
-	if (get_ahci_device_data(port, (u8 *) & fis, 20,
-				 tmpid, sizeof(hd_driveid_t))) {
+	if (ahci_device_data_io(port, (u8 *) &fis, 20, tmpid,
+				sizeof(hd_driveid_t), 0)) {
 		debug("scsi_ahci: SCSI inquiry command failure.\n");
 		return -EIO;
 	}
@@ -590,9 +590,9 @@ static int ata_scsiop_inquiry(ccb *pccb)
 
 
 /*
- * SCSI READ10 command operation.
+ * SCSI READ10/WRITE10 command operation.
  */
-static int ata_scsiop_read10(ccb * pccb)
+static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 {
 	u32 lba = 0;
 	u16 blocks = 0;
@@ -616,20 +616,21 @@ static int ata_scsiop_read10(ccb * pccb)
 	 */
 	blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]);
 
-	debug("scsi_ahci: read %d blocks starting from lba 0x%x\n",
-	      (unsigned)lba, blocks);
+	debug("scsi_ahci: %s %d blocks starting from lba 0x%x\n",
+	      is_write ?  "write" : "read", (unsigned)lba, blocks);
 
 	/* Preset the FIS */
 	memset(fis, 0, 20);
 	fis[0] = 0x27;		 /* Host to device FIS. */
 	fis[1] = 1 << 7;	 /* Command FIS. */
-	fis[2] = ATA_CMD_RD_DMA; /* Command byte. */
+	/* Command byte (read/write). */
+	fis[2] = is_write ? ATA_CMD_WR_DMA : ATA_CMD_RD_DMA;
 
 	while (blocks) {
 		u16 now_blocks; /* number of blocks per iteration */
 		u32 transfer_size; /* number of bytes per iteration */
 
-		now_blocks = min(MAX_SATA_BLOCKS_READ, blocks);
+		now_blocks = min(MAX_SATA_BLOCKS_READ_WRITE, blocks);
 
 		transfer_size = ATA_BLOCKSIZE * now_blocks;
 		if (transfer_size > user_buffer_size) {
@@ -647,10 +648,12 @@ static int ata_scsiop_read10(ccb * pccb)
 		fis[12] = (now_blocks >> 0) & 0xff;
 		fis[13] = (now_blocks >> 8) & 0xff;
 
-		/* Read from ahci */
-		if (get_ahci_device_data(pccb->target, (u8 *) &fis, sizeof(fis),
-					 user_buffer, user_buffer_size)) {
-			debug("scsi_ahci: SCSI READ10 command failure.\n");
+		/* Read/Write from ahci */
+		if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis),
+					user_buffer, user_buffer_size,
+					is_write)) {
+			debug("scsi_ahci: SCSI %s10 command failure.\n",
+			      is_write ? "WRITE" : "READ");
 			return -EIO;
 		}
 		user_buffer += transfer_size;
@@ -703,7 +706,10 @@ int scsi_exec(ccb *pccb)
 
 	switch (pccb->cmd[0]) {
 	case SCSI_READ10:
-		ret = ata_scsiop_read10(pccb);
+		ret = ata_scsiop_read_write(pccb, 0);
+		break;
+	case SCSI_WRITE10:
+		ret = ata_scsiop_read_write(pccb, 1);
 		break;
 	case SCSI_RD_CAPAC:
 		ret = ata_scsiop_read_capacity10(pccb);
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 11/22] ahci: Make the AHCI code find the capacity of disks > 128 GB properly
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (9 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 10/22] ahci: support scsi writing in AHCI driver Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 12/22] ahci: Use sizeof(fis) instead of hardcoding '20' Simon Glass
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Gabe Black <gabeblack@chromium.org>

In the structure returned by the ATA identify device command, there are two
fields which describe the device capacity. One is a 32 bit data type which
reports the number of sectors as a 28 bit LBA, and the other is a 64 bit data
type which is for a 48 bit LBA. If the device doesn't support 48 bit LBAs,
the small value is the only value with the correct size. If it supports more,
if the number of sectors is small enough to fit into 28 bits, both fields
reflect the correct value. If it's too large, the smaller field has 28 bits of
1s, 0xfffffff, and the other field has the correct value.

The AHCI driver is implemented by attaching to the generic SCSI code and
translating on the fly between SCSI binary data structures and AHCI data
structures. It responds to requests to execute specific SCSI commands by
executing the equivalent AHCI commands and then crafting a response which
matches what a SCSI disk would send.

The AHCI driver now considers both fields and chooses the correct one when
implementing both the SCSI READ CAPACITY (10) and READ CAPACITY (16) commands.

Signed-off-by: Gabe Black <gabeblack@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   55 +++++++++++++++++++++++++++++++++++++++++++++----
 include/scsi.h       |    2 +
 2 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 5092352..c16e8ba 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -672,6 +672,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 static int ata_scsiop_read_capacity10(ccb *pccb)
 {
 	u32 cap;
+	u32 block_size;
 
 	if (!ataid[pccb->target]) {
 		printf("scsi_ahci: SCSI READ CAPACITY10 command failure. "
@@ -680,12 +681,53 @@ static int ata_scsiop_read_capacity10(ccb *pccb)
 		return -EPERM;
 	}
 
-	cap = be32_to_cpu(ataid[pccb->target]->lba_capacity);
+	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]));
+		}
+	}
+
+	cap = cpu_to_be32(cap);
 	memcpy(pccb->pdata, &cap, sizeof(cap));
 
-	pccb->pdata[4] = pccb->pdata[5] = 0;
-	pccb->pdata[6] = 512 >> 8;
-	pccb->pdata[7] = 512 & 0xff;
+	block_size = cpu_to_be32((u32)512);
+	memcpy(&pccb->pdata[4], &block_size, 4);
+
+	return 0;
+}
+
+
+/*
+ * SCSI READ CAPACITY16 command operation.
+ */
+static int ata_scsiop_read_capacity16(ccb *pccb)
+{
+	u64 cap;
+	u64 block_size;
+
+	if (!ataid[pccb->target]) {
+		printf("scsi_ahci: SCSI READ CAPACITY16 command failure. "
+		       "\tNo ATA info!\n"
+		       "\tPlease run SCSI commmand INQUIRY firstly!\n");
+		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 = cpu_to_be64(cap);
+	memcpy(pccb->pdata, &cap, sizeof(cap));
+
+	block_size = cpu_to_be64((u64)512);
+	memcpy(&pccb->pdata[8], &block_size, 8);
 
 	return 0;
 }
@@ -711,9 +753,12 @@ int scsi_exec(ccb *pccb)
 	case SCSI_WRITE10:
 		ret = ata_scsiop_read_write(pccb, 1);
 		break;
-	case SCSI_RD_CAPAC:
+	case SCSI_RD_CAPAC10:
 		ret = ata_scsiop_read_capacity10(pccb);
 		break;
+	case SCSI_RD_CAPAC16:
+		ret = ata_scsiop_read_capacity16(pccb);
+		break;
 	case SCSI_TST_U_RDY:
 		ret = ata_scsiop_test_unit_ready(pccb);
 		break;
diff --git a/include/scsi.h b/include/scsi.h
index 9681d19..9da764b 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -150,6 +150,8 @@ typedef struct SCSI_cmd_block{
 #define SCSI_READ6		0x08		/* Read 6-byte (MANDATORY) */
 #define SCSI_READ10		0x28		/* Read 10-byte (MANDATORY) */
 #define SCSI_RD_CAPAC	0x25		/* Read Capacity (MANDATORY) */
+#define SCSI_RD_CAPAC10	SCSI_RD_CAPAC	/* Read Capacity (10) */
+#define SCSI_RD_CAPAC16	0x9e		/* Read Capacity (16) */
 #define SCSI_RD_DEFECT	0x37		/* Read Defect Data (O) */
 #define SCSI_READ_LONG	0x3E		/* Read Long (O) */
 #define SCSI_REASS_BLK	0x07		/* Reassign Blocks (O) */
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 12/22] ahci: Use sizeof(fis) instead of hardcoding '20'
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (10 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 11/22] ahci: Make the AHCI code find the capacity of disks > 128 GB properly Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 13/22] ahci: Fix 'Invaild' typo Simon Glass
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Taylor Hutt <thutt@chromium.org>

This cleanup replaces the hardcoded use of '20', which represents the
number of bytes in the FIS, with sizeof(fis).

Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index c16e8ba..10fae88 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -383,14 +383,14 @@ static void ahci_set_feature(u8 port)
 	u8 fis[20];
 
 	/* set feature */
-	memset(fis, 0, 20);
+	memset(fis, 0, sizeof(fis));
 	fis[0] = 0x27;
 	fis[1] = 1 << 7;
 	fis[2] = ATA_CMD_SETF;
 	fis[3] = SETFEATURES_XFER;
 	fis[12] = __ilog2(probe_ent->udma_mask + 1) + 0x40 - 0x01;
 
-	memcpy((unsigned char *)pp->cmd_tbl, fis, 20);
+	memcpy((unsigned char *)pp->cmd_tbl, fis, sizeof(fis));
 	ahci_fill_cmd_slot(pp, cmd_fis_len);
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 	readl(port_mmio + PORT_CMD_ISSUE);
@@ -559,7 +559,7 @@ static int ata_scsiop_inquiry(ccb *pccb)
 	if (pccb->datalen <= 35)
 		return 0;
 
-	memset(fis, 0, 20);
+	memset(fis, 0, sizeof(fis));
 	/* Construct the FIS */
 	fis[0] = 0x27;		/* Host to device FIS. */
 	fis[1] = 1 << 7;	/* Command FIS. */
@@ -570,7 +570,7 @@ static int ata_scsiop_inquiry(ccb *pccb)
 	if (!(tmpid = malloc(sizeof(hd_driveid_t))))
 		return -ENOMEM;
 
-	if (ahci_device_data_io(port, (u8 *) &fis, 20, tmpid,
+	if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), tmpid,
 				sizeof(hd_driveid_t), 0)) {
 		debug("scsi_ahci: SCSI inquiry command failure.\n");
 		return -EIO;
@@ -620,7 +620,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 	      is_write ?  "write" : "read", (unsigned)lba, blocks);
 
 	/* Preset the FIS */
-	memset(fis, 0, 20);
+	memset(fis, 0, sizeof(fis));
 	fis[0] = 0x27;		 /* Host to device FIS. */
 	fis[1] = 1 << 7;	 /* Command FIS. */
 	/* Command byte (read/write). */
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 13/22] ahci: Fix 'Invaild' typo
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (11 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 12/22] ahci: Use sizeof(fis) instead of hardcoding '20' Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 14/22] ahci: Support 64-bit LBA option when reading capacity Simon Glass
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Taylor Hutt <thutt@chromium.org>

This fixes a spelling error in a message which can be output to the
console.

Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Move #ifdef change into earlier commit

 drivers/block/ahci.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 10fae88..20c5336 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -478,7 +478,7 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
 	debug("Enter %s: for port %d\n", __func__, port);
 
 	if (port > probe_ent->n_ports) {
-		printf("Invaild port number %d\n", port);
+		printf("Invalid port number %d\n", port);
 		return -1;
 	}
 
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 14/22] ahci: Support 64-bit LBA option when reading capacity
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (12 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 13/22] ahci: Fix 'Invaild' typo Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 15/22] ahci: Use virt_to_phys() to denote physical addresses for DMA Simon Glass
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Gabe Black <gabeblack@chromium.org>

Capacity needs to allow for a 64-bit value.

Signed-off-by: Gabe Black <gabeblack@google.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Add patch to support 64-bit LBA option when reading capacity

 common/cmd_scsi.c |   92 ++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c
index 9bd8ec9..266bfa6 100644
--- a/common/cmd_scsi.c
+++ b/common/cmd_scsi.c
@@ -72,7 +72,6 @@ static block_dev_desc_t scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
  *  forward declerations of some Setup Routines
  */
 void scsi_setup_test_unit_ready(ccb * pccb);
-void scsi_setup_read_capacity(ccb * pccb);
 void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);
 void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);
 static void scsi_setup_write_ext(ccb *pccb, unsigned long start,
@@ -81,6 +80,8 @@ void scsi_setup_inquiry(ccb * pccb);
 void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
 
 
+static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity,
+			      unsigned long *blksz);
 static ulong scsi_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer);
 static ulong scsi_write(int device, ulong blknr,
 			lbaint_t blkcnt, const void *buffer);
@@ -93,7 +94,8 @@ static ulong scsi_write(int device, ulong blknr,
 void scsi_scan(int mode)
 {
 	unsigned char i,perq,modi,lun;
-	unsigned long capacity,blksz;
+	lbaint_t capacity;
+	unsigned long blksz;
 	ccb* pccb=(ccb *)&tempccb;
 
 	if(mode==1) {
@@ -158,16 +160,10 @@ void scsi_scan(int mode)
 				scsi_print_error(pccb);
 				continue;
 			}
-			pccb->datalen=8;
-			scsi_setup_read_capacity(pccb);
-			if(scsi_exec(pccb)!=TRUE) {
+			if (scsi_read_capacity(pccb, &capacity, &blksz)) {
 				scsi_print_error(pccb);
 				continue;
 			}
-			capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)|
-					((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]);
-			blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)|
-				((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]);
 			scsi_dev_desc[scsi_max_devs].lba=capacity;
 			scsi_dev_desc[scsi_max_devs].blksz=blksz;
 			scsi_dev_desc[scsi_max_devs].type=perq;
@@ -514,6 +510,67 @@ void scsi_trim_trail (unsigned char *str, unsigned int len)
 	}
 }
 
+int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz)
+{
+	*capacity = 0;
+
+	memset(pccb->cmd, 0, sizeof(pccb->cmd));
+	pccb->cmd[0] = SCSI_RD_CAPAC10;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmdlen = 10;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+	pccb->datalen = 8;
+	if (scsi_exec(pccb) != TRUE)
+		return 1;
+
+	*capacity = ((lbaint_t)pccb->pdata[0] << 24) |
+		    ((lbaint_t)pccb->pdata[1] << 16) |
+		    ((lbaint_t)pccb->pdata[2] << 8)  |
+		    ((lbaint_t)pccb->pdata[3]);
+
+	if (*capacity != 0xffffffff) {
+		/* Read capacity (10) was sufficient for this drive. */
+		*blksz = ((unsigned long)pccb->pdata[4] << 24) |
+			 ((unsigned long)pccb->pdata[5] << 16) |
+			 ((unsigned long)pccb->pdata[6] << 8)  |
+			 ((unsigned long)pccb->pdata[7]);
+		return 0;
+	}
+
+	/* Read capacity (10) was insufficient. Use read capacity (16). */
+
+	memset(pccb->cmd, 0, sizeof(pccb->cmd));
+	pccb->cmd[0] = SCSI_RD_CAPAC16;
+	pccb->cmd[1] = 0x10;
+	pccb->cmdlen = 16;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+	pccb->datalen = 16;
+	if (scsi_exec(pccb) != TRUE)
+		return 1;
+
+	*capacity = ((uint64_t)pccb->pdata[0] << 56) |
+		    ((uint64_t)pccb->pdata[1] << 48) |
+		    ((uint64_t)pccb->pdata[2] << 40) |
+		    ((uint64_t)pccb->pdata[3] << 32) |
+		    ((uint64_t)pccb->pdata[4] << 24) |
+		    ((uint64_t)pccb->pdata[5] << 16) |
+		    ((uint64_t)pccb->pdata[6] << 8)  |
+		    ((uint64_t)pccb->pdata[7]);
+
+	*blksz = ((uint64_t)pccb->pdata[8]  << 56) |
+		 ((uint64_t)pccb->pdata[9]  << 48) |
+		 ((uint64_t)pccb->pdata[10] << 40) |
+		 ((uint64_t)pccb->pdata[11] << 32) |
+		 ((uint64_t)pccb->pdata[12] << 24) |
+		 ((uint64_t)pccb->pdata[13] << 16) |
+		 ((uint64_t)pccb->pdata[14] << 8)  |
+		 ((uint64_t)pccb->pdata[15]);
+
+	return 0;
+}
+
 
 /************************************************************************************
  * Some setup (fill-in) routines
@@ -530,23 +587,6 @@ void scsi_setup_test_unit_ready(ccb * pccb)
 	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
 }
 
-void scsi_setup_read_capacity(ccb * pccb)
-{
-	pccb->cmd[0]=SCSI_RD_CAPAC;
-	pccb->cmd[1]=pccb->lun<<5;
-	pccb->cmd[2]=0;
-	pccb->cmd[3]=0;
-	pccb->cmd[4]=0;
-	pccb->cmd[5]=0;
-	pccb->cmd[6]=0;
-	pccb->cmd[7]=0;
-	pccb->cmd[8]=0;
-	pccb->cmd[9]=0;
-	pccb->cmdlen=10;
-	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-
-}
-
 void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks)
 {
 	pccb->cmd[0]=SCSI_READ10;
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 15/22] ahci: Use virt_to_phys() to denote physical addresses for DMA
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (13 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 14/22] ahci: Support 64-bit LBA option when reading capacity Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 16/22] ahci: flush / invalidate dcache around SATA commands Simon Glass
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Taylor Hutt <thutt@chromium.org>

Update the assignment of various physical memory buffers used by the
SATA controller to explicitly be denoted as physical addresses.

The memory is identity-mapped, so these function calls are a nop, but
they provide good semantic documentation for any maintainers.

The return value of virt_to_phys() is 'unsigned long'.  On machines
where sizeof(unsigned long) != sizeof(pointer), a cast through
(uintptr_t) is needed to appease the compiler due to the potential of
losing the upper 32 bits of the address.

In compilation this scenario, a physical address could be 64-bits, yet
the C pointer environment only allows 32-bit addresses; the constraint
is that pointers cannot address more than 4Gb of memory and if
virt_to_phys() ever returns an out-of-range value for the physical
address, there are issues with emmory mapping which must be solved.
However, since the memory is identify mappeed, there is no problem
introducing the cast: the original pointer will reside in 32-bits, so
the physical address will also be within in 32-bits.

Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 20c5336..00de086 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -431,25 +431,27 @@ static int ahci_port_start(u8 port)
 	 * First item in chunk of DMA memory: 32-slot command table,
 	 * 32 bytes each in size
 	 */
-	pp->cmd_slot = (struct ahci_cmd_hdr *)mem;
+	pp->cmd_slot =
+		(struct ahci_cmd_hdr *)(uintptr_t)virt_to_phys((void *)mem);
 	debug("cmd_slot = 0x%x\n", (unsigned)pp->cmd_slot);
 	mem += (AHCI_CMD_SLOT_SZ + 224);
 
 	/*
 	 * Second item: Received-FIS area
 	 */
-	pp->rx_fis = mem;
+	pp->rx_fis = virt_to_phys((void *)mem);
 	mem += AHCI_RX_FIS_SZ;
 
 	/*
 	 * Third item: data area for storing a single command
 	 * and its scatter-gather table
 	 */
-	pp->cmd_tbl = mem;
+	pp->cmd_tbl = virt_to_phys((void *)mem);
 	debug("cmd_tbl_dma = 0x%x\n", pp->cmd_tbl);
 
 	mem += AHCI_CMD_TBL_HDR;
-	pp->cmd_tbl_sg = (struct ahci_sg *)mem;
+	pp->cmd_tbl_sg =
+			(struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem);
 
 	writel_with_flush((u32) pp->cmd_slot, port_mmio + PORT_LST_ADDR);
 
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 16/22] ahci: flush / invalidate dcache around SATA commands
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (14 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 15/22] ahci: Use virt_to_phys() to denote physical addresses for DMA Simon Glass
@ 2012-10-29 15:23 ` Simon Glass
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 17/22] ahci: Adjust SATA timeouts for hard disk (spinup delay & command timeout) Simon Glass
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:23 UTC (permalink / raw)
  To: u-boot

From: Taylor Hutt <thutt@chromium.org>

Exynos5 automatically performs DMA when the SATA controller executes
commands.  This adds the necessary dcache-to-memory flush &
invalidation calls to allow the DMA to properly function.

Signed-off-by: Taylor Hutt <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 00de086..a05d9cf 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -70,6 +70,39 @@ static void ahci_setup_port(struct ahci_ioports *port, unsigned long base,
 
 #define msleep(a) udelay(a * 1000)
 
+static void ahci_dcache_flush_range(unsigned begin, unsigned len)
+{
+	const unsigned long start = begin;
+	const unsigned long end = start + len;
+
+	debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end);
+	flush_dcache_range(start, end);
+}
+
+/*
+ * SATA controller DMAs to physical RAM.  Ensure data from the
+ * controller is invalidated from dcache; next access comes from
+ * physical RAM.
+ */
+static void ahci_dcache_invalidate_range(unsigned begin, unsigned len)
+{
+	const unsigned long start = begin;
+	const unsigned long end = start + len;
+
+	debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end);
+	invalidate_dcache_range(start, end);
+}
+
+/*
+ * Ensure data for SATA controller is flushed out of dcache and
+ * written to physical memory.
+ */
+static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp)
+{
+	ahci_dcache_flush_range((unsigned long)pp->cmd_slot,
+				AHCI_PORT_PRIV_DMA_SZ);
+}
+
 static int waiting_for_cmd_completed(volatile u8 *offset,
 				     int timeout_msec,
 				     u32 sign)
@@ -392,6 +425,7 @@ static void ahci_set_feature(u8 port)
 
 	memcpy((unsigned char *)pp->cmd_tbl, fis, sizeof(fis));
 	ahci_fill_cmd_slot(pp, cmd_fis_len);
+	ahci_dcache_flush_sata_cmd(pp);
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 	readl(port_mmio + PORT_CMD_ISSUE);
 
@@ -496,12 +530,17 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
 	opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6);
 	ahci_fill_cmd_slot(pp, opts);
 
+	ahci_dcache_flush_sata_cmd(pp);
+	ahci_dcache_flush_range((unsigned)buf, (unsigned)buf_len);
+
 	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;
 	}
+
+	ahci_dcache_invalidate_range((unsigned)buf, (unsigned)buf_len);
 	debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status);
 
 	return 0;
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 17/22] ahci: Adjust SATA timeouts for hard disk (spinup delay & command timeout)
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (15 preceding siblings ...)
  2012-10-29 15:23 ` [U-Boot] [PATCH v3 16/22] ahci: flush / invalidate dcache around SATA commands Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 18/22] ahci: Support spin-up and link-up separately Simon Glass
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

From: Walter Murphy <wmurphy@google.com>

Note: These are timeout values and not delay values, so the event being
timed out will complete whenever it is actually ready, with a
measurement granularity of 1 millisecond, up till the timeout value.
Therefore, there is no effect on SSD booting.

The values were determined by instrumenting the code and measuring the
actual time taken by several different models of HDD for each of the
parameters and then adding 50% more for the spinup value and just
doubling the command timeout value.

Signed-off-by: Walter Murphy <wmurphy@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index a05d9cf..719574f 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -52,6 +52,10 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];
 #define MAX_SATA_BLOCKS_READ_WRITE	0x80
 #endif
 
+/* Maximum timeouts for each event */
+#define WAIT_MS_DATAIO	5000
+#define WAIT_MS_LINKUP	4
+
 static inline u32 ahci_port_base(u32 base, u32 port)
 {
 	return base + 0x100 + (port * 0x80);
@@ -201,14 +205,14 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 		writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
 
 		j = 0;
-		while (j < 1000) {
+		while (j < WAIT_MS_LINKUP) {
 			tmp = readl(port_mmio + PORT_SCR_STAT);
 			if ((tmp & 0xf) == 0x3)
 				break;
 			udelay(1000);
 			j++;
 		}
-		if (j == 1000)
+		if (j == WAIT_MS_LINKUP)
 			debug("timeout.\n");
 		else
 			debug("ok.\n");
@@ -429,7 +433,8 @@ static void ahci_set_feature(u8 port)
 	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)) {
+	if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE,
+				WAIT_MS_DATAIO, 0x1)) {
 		printf("set feature error on port %d!\n", port);
 	}
 }
@@ -535,7 +540,8 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
 
 	writel_with_flush(1, port_mmio + PORT_CMD_ISSUE);
 
-	if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) {
+	if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE,
+				WAIT_MS_DATAIO, 0x1)) {
 		printf("timeout exit!\n");
 		return -1;
 	}
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 18/22] ahci: Support spin-up and link-up separately
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (16 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 17/22] ahci: Adjust SATA timeouts for hard disk (spinup delay & command timeout) Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 19/22] ahci: Perform SATA flush after disk write Simon Glass
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

From: Marc Jones <marc.jones@chromium.org>

Add HDD handling to the SSD-only AHCI driver, by separately dealing with
spin-up and link-up.

Signed-off-by: Marc Jones <marc.jones@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   45 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 719574f..19c5f13 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -53,6 +53,7 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];
 #endif
 
 /* Maximum timeouts for each event */
+#define WAIT_MS_SPINUP	10000
 #define WAIT_MS_DATAIO	5000
 #define WAIT_MS_LINKUP	4
 
@@ -129,7 +130,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 	unsigned short vendor;
 #endif
 	volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;
-	u32 tmp, cap_save;
+	u32 tmp, cap_save, cmd;
 	int i, j;
 	volatile u8 *port_mmio;
 
@@ -137,7 +138,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 
 	cap_save = readl(mmio + HOST_CAP);
 	cap_save &= ((1 << 28) | (1 << 17));
-	cap_save |= (1 << 27);
+	cap_save |= (1 << 27);  /* Staggered Spin-up. Not needed. */
 
 	/* global controller reset */
 	tmp = readl(mmio + HOST_CTL);
@@ -201,9 +202,18 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 			msleep(500);
 		}
 
-		debug("Spinning up port %d... ", i);
-		writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
-
+		/* Add the spinup command to whatever mode bits may
+		 * already be on in the command register.
+		 */
+		cmd = readl(port_mmio + PORT_CMD);
+		cmd |= PORT_CMD_FIS_RX;
+		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);
@@ -212,7 +222,30 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 			udelay(1000);
 			j++;
 		}
-		if (j == WAIT_MS_LINKUP)
+		if (j == WAIT_MS_LINKUP) {
+			printf("SATA link %d timeout.\n", i);
+			continue;
+		} else {
+			debug("SATA link ok.\n");
+		}
+
+		/* Clear error status */
+		tmp = readl(port_mmio + PORT_SCR_ERR);
+		if (tmp)
+			writel(tmp, port_mmio + PORT_SCR_ERR);
+
+		debug("Spinning up device on SATA port %d... ", i);
+
+		j = 0;
+		while (j < WAIT_MS_SPINUP) {
+			tmp = readl(port_mmio + PORT_TFDATA);
+			if (!(tmp & (ATA_STAT_BUSY | ATA_STAT_DRQ)))
+				break;
+			udelay(1000);
+			j++;
+		}
+		printf("Target spinup took %d ms.\n", j);
+		if (j == WAIT_MS_SPINUP)
 			debug("timeout.\n");
 		else
 			debug("ok.\n");
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 19/22] ahci: Perform SATA flush after disk write.
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (17 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 18/22] ahci: Support spin-up and link-up separately Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 20/22] ahci: Expand HDD Logical Block addressability up to 32 bits Simon Glass
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

From: Marc Jones <marc.jones@chromium.org>

Writes in u-boot are so rare, and the logic to know when is
the last write and do a flush only there is sufficiently
difficult. Just do a flush after every write. This incurs,
usually, one extra flush when the rare writes do happen.

Signed-off-by: Marc Jones <marc.jones@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++-
 include/ata.h        |    3 ++
 2 files changed, 54 insertions(+), 1 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 19c5f13..963efec 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -37,6 +37,8 @@
 #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];
 
@@ -55,6 +57,7 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];
 /* Maximum timeouts for each event */
 #define WAIT_MS_SPINUP	10000
 #define WAIT_MS_DATAIO	5000
+#define WAIT_MS_FLUSH	5000
 #define WAIT_MS_LINKUP	4
 
 static inline u32 ahci_port_base(u32 base, u32 port)
@@ -267,7 +270,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 
 		/* register linkup ports */
 		tmp = readl(port_mmio + PORT_SCR_STAT);
-		debug("Port %d status: 0x%x\n", i, tmp);
+		debug("SATA port %d status: 0x%x\n", i, tmp);
 		if ((tmp & 0xf) == 0x03)
 			probe_ent->link_port_map |= (0x01 << i);
 	}
@@ -736,6 +739,17 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 			      is_write ? "WRITE" : "READ");
 			return -EIO;
 		}
+
+		/* If this transaction is a write, do a following flush.
+		 * Writes in u-boot are so rare, and the logic to know when is
+		 * the last write and do a flush only there is sufficiently
+		 * difficult. Just do a flush after every write. This incurs,
+		 * usually, one extra flush when the rare writes do happen.
+		 */
+		if (is_write) {
+			if (-EIO == ata_io_flush(pccb->target))
+				return -EIO;
+		}
 		user_buffer += transfer_size;
 		user_buffer_size -= transfer_size;
 		blocks -= now_blocks;
@@ -929,6 +943,42 @@ err_out:
 }
 #endif
 
+/*
+ * In the general case of generic rotating media it makes sense to have a
+ * flush capability. It probably even makes sense in the case of SSDs because
+ * one cannot always know for sure what kind of internal cache/flush mechanism
+ * is embodied therein. At first it was planned to invoke this after the last
+ * write to disk and before rebooting. In practice, knowing, a priori, which
+ * is the last write is difficult. Because writing to the disk in u-boot is
+ * very rare, this flush command will be invoked after every block write.
+ */
+static int ata_io_flush(u8 port)
+{
+	u8 fis[20];
+	struct ahci_ioports *pp = &(probe_ent->port[port]);
+	volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio;
+	u32 cmd_fis_len = 5;	/* five dwords */
+
+	/* Preset the FIS */
+	memset(fis, 0, 20);
+	fis[0] = 0x27;		 /* Host to device FIS. */
+	fis[1] = 1 << 7;	 /* Command FIS. */
+	fis[2] = ATA_CMD_FLUSH;
+
+	memcpy((unsigned char *)pp->cmd_tbl, fis, 20);
+	ahci_fill_cmd_slot(pp, cmd_fis_len);
+	writel_with_flush(1, port_mmio + PORT_CMD_ISSUE);
+
+	if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE,
+			WAIT_MS_FLUSH, 0x1)) {
+		debug("scsi_ahci: flush command timeout on port %d.\n", port);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
 void scsi_bus_reset(void)
 {
 	/*Not implement*/
diff --git a/include/ata.h b/include/ata.h
index 3b2d737..a614724 100644
--- a/include/ata.h
+++ b/include/ata.h
@@ -114,6 +114,9 @@
 #define ATA_CMD_WRITE_EXT	0x34	/* Write Sectores (with retries) with 48bit addressing */
 #define ATA_CMD_VRFY_EXT	0x42	/* Read Verify	(with retries)	with 48bit addressing */
 
+#define ATA_CMD_FLUSH 0xE7 /* Flush drive cache */
+#define ATA_CMD_FLUSH_EXT 0xEA /* Flush drive cache, with 48bit addressing */
+
 /*
  * ATAPI Commands
  */
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 20/22] ahci: Expand HDD Logical Block addressability up to 32 bits
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (18 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 19/22] ahci: Perform SATA flush after disk write Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write() Simon Glass
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

From: Walter Murphy <wmurphy@google.com>

Currently, this driver uses a 28bit interface to AHCI, this
limits the number of blocks addressable to 2^28, or the max
disk size to 512(2^28) or about 137GB. This change allows
supporting drives up to about 2TB.

Testing this is a bit difficult. There is test code that
can be inserted into U-Boot that will write test patterns
into certain unused blocks. These patterns can be manually
checked using 'dd' after boot. Another way is to confirm the
original error that exposed this bug is fixed. IOW: see if
AU (Auto Update) will now work on the drive. Also, check
that there are no warning messages from the 'cgpt' utility.

Signed-off-by: Walter Murphy <wmurphy@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 963efec..8c785ae 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -707,7 +707,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 	fis[0] = 0x27;		 /* Host to device FIS. */
 	fis[1] = 1 << 7;	 /* Command FIS. */
 	/* Command byte (read/write). */
-	fis[2] = is_write ? ATA_CMD_WR_DMA : ATA_CMD_RD_DMA;
+	fis[2] = is_write ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT;
 
 	while (blocks) {
 		u16 now_blocks; /* number of blocks per iteration */
@@ -721,11 +721,15 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
 			return -EIO;
 		}
 
-		/* LBA address, only support LBA28 in this driver */
+		/* LBA48 SATA command but only use 32bit address range within
+		 * that. The next smaller command range (28bit) is too small.
+		 */
 		fis[4] = (lba >> 0) & 0xff;
 		fis[5] = (lba >> 8) & 0xff;
 		fis[6] = (lba >> 16) & 0xff;
-		fis[7] = ((lba >> 24) & 0xf) | 0xe0;
+		fis[7] = 1 << 6; /* device reg: set LBA mode */
+		fis[8] = ((lba >> 24) & 0xff);
+		fis[3] = 0xe0; /* features */
 
 		/* Block (sector) count */
 		fis[12] = (now_blocks >> 0) & 0xff;
@@ -963,7 +967,7 @@ static int ata_io_flush(u8 port)
 	memset(fis, 0, 20);
 	fis[0] = 0x27;		 /* Host to device FIS. */
 	fis[1] = 1 << 7;	 /* Command FIS. */
-	fis[2] = ATA_CMD_FLUSH;
+	fis[2] = ATA_CMD_FLUSH_EXT;
 
 	memcpy((unsigned char *)pp->cmd_tbl, fis, 20);
 	ahci_fill_cmd_slot(pp, cmd_fis_len);
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write()
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (19 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 20/22] ahci: Expand HDD Logical Block addressability up to 32 bits Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-10-29 18:22   ` Tom Rini
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 22/22] x86: config: Enable AHCI support for coreboot Simon Glass
  2012-11-04 18:29 ` [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Tom Rini
  22 siblings, 1 reply; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

The prototypes in the header were changed by commit 4ac8f8e0 but the
functions no longer match. Correct this.

It seems odd that block devices take an lbaint_t for the block count, but
an unsigned long for the blknr. Surely we should promote blknr to lbaint_t
also?

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Add new patch to correct ide_read/write() function signatures

 common/cmd_ide.c |   27 +++++++++------------------
 1 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/common/cmd_ide.c b/common/cmd_ide.c
index d508e9f..0105bdb 100644
--- a/common/cmd_ide.c
+++ b/common/cmd_ide.c
@@ -96,7 +96,8 @@ static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len
 
 #ifdef CONFIG_ATAPI
 static void	atapi_inquiry(block_dev_desc_t *dev_desc);
-ulong atapi_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer);
+static ulong atapi_read(int device, ulong blknr, lbaint_t blkcnt,
+			void *buffer);
 #endif
 
 
@@ -826,7 +827,7 @@ static void ide_ident(block_dev_desc_t *dev_desc)
 
 /* ------------------------------------------------------------------------- */
 
-ulong ide_read(int device, lbaint_t blknr, ulong blkcnt, void *buffer)
+ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
 {
 	ulong n = 0;
 	unsigned char c;
@@ -840,7 +841,7 @@ ulong ide_read(int device, lbaint_t blknr, ulong blkcnt, void *buffer)
 		lba48 = 1;
 	}
 #endif
-	debug("ide_read dev %d start %lX, blocks %lX buffer at %lX\n",
+	debug("ide_read dev %d start %lX, blocks " LBAF " buffer at %lX\n",
 	      device, blknr, blkcnt, (ulong) buffer);
 
 	ide_led(DEVICE_LED(device), 1);	/* LED on       */
@@ -930,13 +931,8 @@ ulong ide_read(int device, lbaint_t blknr, ulong blkcnt, void *buffer)
 
 		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
 		    ATA_STAT_DRQ) {
-#if defined(CONFIG_SYS_64BIT_LBA)
-			printf("Error (no IRQ) dev %d blk %lld: status 0x%02x\n",
+			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n",
 				device, blknr, c);
-#else
-			printf("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
-				device, (ulong) blknr, c);
-#endif
 			break;
 		}
 
@@ -955,7 +951,7 @@ IDE_READ_E:
 /* ------------------------------------------------------------------------- */
 
 
-ulong ide_write(int device, lbaint_t blknr, ulong blkcnt, const void *buffer)
+ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer)
 {
 	ulong n = 0;
 	unsigned char c;
@@ -1023,13 +1019,8 @@ ulong ide_write(int device, lbaint_t blknr, ulong blkcnt, const void *buffer)
 
 		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
 		    ATA_STAT_DRQ) {
-#if defined(CONFIG_SYS_64BIT_LBA)
-			printf("Error (no IRQ) dev %d blk %lld: status 0x%02x\n",
+			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n",
 				device, blknr, c);
-#else
-			printf("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
-				device, (ulong) blknr, c);
-#endif
 			goto WR_OUT;
 		}
 
@@ -1518,13 +1509,13 @@ static void atapi_inquiry(block_dev_desc_t *dev_desc)
 #define ATAPI_READ_BLOCK_SIZE	2048	/* assuming CD part */
 #define ATAPI_READ_MAX_BLOCK	(ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE)
 
-ulong atapi_read(int device, lbaint_t blknr, ulong blkcnt, void *buffer)
+ulong atapi_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
 {
 	ulong n = 0;
 	unsigned char ccb[12];	/* Command descriptor block */
 	ulong cnt;
 
-	debug("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n",
+	debug("atapi_read dev %d start %lX, blocks " LBAF " buffer at %lX\n",
 	      device, blknr, blkcnt, (ulong) buffer);
 
 	do {
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 22/22] x86: config: Enable AHCI support for coreboot
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (20 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write() Simon Glass
@ 2012-10-29 15:24 ` Simon Glass
  2012-11-04 18:29 ` [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Tom Rini
  22 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 15:24 UTC (permalink / raw)
  To: u-boot

Enable AHCI driver for Intel SATA devices.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 include/configs/coreboot.h |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index 3df085b..cc95e2b 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -45,6 +45,28 @@
 #undef CONFIG_WATCHDOG
 #undef CONFIG_HW_WATCHDOG
 
+/* SATA AHCI storage */
+
+#define CONFIG_SCSI_AHCI
+
+#ifdef CONFIG_SCSI_AHCI
+#define CONFIG_SYS_64BIT_LBA
+#define CONFIG_SATA_INTEL		1
+#define CONFIG_SCSI_DEV_LIST		{PCI_VENDOR_ID_INTEL, \
+			PCI_DEVICE_ID_INTEL_NM10_AHCI},	      \
+	{PCI_VENDOR_ID_INTEL,		\
+			PCI_DEVICE_ID_INTEL_COUGARPOINT_AHCI_MOBILE}, \
+	{PCI_VENDOR_ID_INTEL, \
+			PCI_DEVICE_ID_INTEL_COUGARPOINT_AHCI_SERIES6}, \
+	{PCI_VENDOR_ID_INTEL,		\
+			PCI_DEVICE_ID_INTEL_PANTHERPOINT_AHCI_MOBILE}
+
+#define CONFIG_SYS_SCSI_MAX_SCSI_ID	2
+#define CONFIG_SYS_SCSI_MAX_LUN		1
+#define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
+					 CONFIG_SYS_SCSI_MAX_LUN)
+#endif
+
 /*-----------------------------------------------------------------------
  * Real Time Clock Configuration
  */
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write()
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write() Simon Glass
@ 2012-10-29 18:22   ` Tom Rini
  2012-10-29 18:28     ` Simon Glass
  0 siblings, 1 reply; 26+ messages in thread
From: Tom Rini @ 2012-10-29 18:22 UTC (permalink / raw)
  To: u-boot

On Mon, Oct 29, 2012 at 08:24:04AM -0700, Simon Glass wrote:

> The prototypes in the header were changed by commit 4ac8f8e0 but the
> functions no longer match. Correct this.

Oops, not sure how I missed that.

> It seems odd that block devices take an lbaint_t for the block count, but
> an unsigned long for the blknr. Surely we should promote blknr to lbaint_t
> also?

It's a bit odd, I agree but doc/driver-model/UDM-block.txt promises to
correct this so I went first for consistency in all users.

Reviewed-by: Tom Rini <trini@ti.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121029/a7c7a89a/attachment.pgp>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write()
  2012-10-29 18:22   ` Tom Rini
@ 2012-10-29 18:28     ` Simon Glass
  0 siblings, 0 replies; 26+ messages in thread
From: Simon Glass @ 2012-10-29 18:28 UTC (permalink / raw)
  To: u-boot

Hi,

On Mon, Oct 29, 2012 at 11:22 AM, Tom Rini <trini@ti.com> wrote:
> On Mon, Oct 29, 2012 at 08:24:04AM -0700, Simon Glass wrote:
>
>> The prototypes in the header were changed by commit 4ac8f8e0 but the
>> functions no longer match. Correct this.
>
> Oops, not sure how I missed that.
>
>> It seems odd that block devices take an lbaint_t for the block count, but
>> an unsigned long for the blknr. Surely we should promote blknr to lbaint_t
>> also?
>
> It's a bit odd, I agree but doc/driver-model/UDM-block.txt promises to
> correct this so I went first for consistency in all users.

Yes, it isn't any worse than it was.

>
> Reviewed-by: Tom Rini <trini@ti.com>
>

Thanks,
Simon

> --
> Tom

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements
  2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
                   ` (21 preceding siblings ...)
  2012-10-29 15:24 ` [U-Boot] [PATCH v3 22/22] x86: config: Enable AHCI support for coreboot Simon Glass
@ 2012-11-04 18:29 ` Tom Rini
  22 siblings, 0 replies; 26+ messages in thread
From: Tom Rini @ 2012-11-04 18:29 UTC (permalink / raw)
  To: u-boot

On Mon, Oct 29, 2012 at 08:23:43AM -0700, Simon Glass wrote:

> This series contains a set of improvements for the SATA susbsystem, mostly
> targeted at solid-state drivers and improving start-up time.
> 
> The patches are tested on various x86 Chromebooks.
> 
> Changes in v3:
> - Remove use of DEFINE_PCI_DEVICE_TABLE suggested by siren checkpatch
> - Use struct pci_device_id properly
> - Add new patch to enable setenv_ulong/addr() for powerpc
> - Fix setenv operation to use correct function
> - Move missing #ifdef CONFIG_AHCI_SETFEATURES_XFER from later commit
> - Remove . from end of commit subject
> - Move #ifdef change into earlier commit
> - Add patch to support 64-bit LBA option when reading capacity
> - Add new patch to correct ide_read/write() function signatures
> 
> Changes in v2:
> - Use struct pci_device_id instead of defining new struct scsi_device
> - Squash in CONFIG_PCI patch
> - Set 'scsidevs' environment variable to number of SCSI disks
> 
> Gabe Black (3):
>   ahci: Make sending the SETFEATURES_XFER command optional
>   ahci: Make the AHCI code find the capacity of disks > 128 GB properly
>   ahci: Support 64-bit LBA option when reading capacity
> 
> Hung-Te Lin (2):
>   scsi: Add scsi_write to SCSI driver
>   ahci: support scsi writing in AHCI driver
> 
> Marc Jones (2):
>   ahci: Support spin-up and link-up separately
>   ahci: Perform SATA flush after disk write.
> 
> Simon Glass (3):
>   Support setenv_ulong() and setenv_addr() for powerpc
>   ide: Correct function signatures for ide_read/write()
>   x86: config: Enable AHCI support for coreboot
> 
> Stefan Reinauer (4):
>   scsi: Add function and env var to report number of scsi drives
>   ahci: Optimise AHCI controller reset and start-up
>   ahci: Improve AHCI debugging
>   ahci: cosmetics and cleanup
> 
> Taylor Hutt (4):
>   ahci: Use sizeof(fis) instead of hardcoding '20'
>   ahci: Fix 'Invaild' typo
>   ahci: Use virt_to_phys() to denote physical addresses for DMA
>   ahci: flush / invalidate dcache around SATA commands
> 
> Vadim Bendebury (2):
>   ahci: Support splitting of read transactions into multiple chunks
>   scsi: Provide support for a list of AHCI controllers.
> 
> Walter Murphy (2):
>   ahci: Adjust SATA timeouts for hard disk (spinup delay & command
>     timeout)
>   ahci: Expand HDD Logical Block addressability up to 32 bits
> 
>  README                     |    3 +
>  common/cmd_ide.c           |   27 +--
>  common/cmd_scsi.c          |  255 ++++++++++++++++++++++++----
>  drivers/block/ahci.c       |  401 +++++++++++++++++++++++++++++++++++---------
>  include/ahci.h             |    1 +
>  include/ata.h              |    3 +
>  include/common.h           |    2 +-
>  include/configs/coreboot.h |   22 +++
>  include/scsi.h             |    4 +
>  9 files changed, 585 insertions(+), 133 deletions(-)

For the series, applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121104/971a9cdb/attachment.pgp>

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2012-11-04 18:29 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-29 15:23 [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 01/22] ahci: Support splitting of read transactions into multiple chunks Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 02/22] scsi: Provide support for a list of AHCI controllers Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 03/22] scsi: Add scsi_write to SCSI driver Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 04/22] Support setenv_ulong() and setenv_addr() for powerpc Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 05/22] scsi: Add function and env var to report number of scsi drives Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 06/22] ahci: Optimise AHCI controller reset and start-up Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 07/22] ahci: Improve AHCI debugging Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 08/22] ahci: cosmetics and cleanup Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 09/22] ahci: Make sending the SETFEATURES_XFER command optional Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 10/22] ahci: support scsi writing in AHCI driver Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 11/22] ahci: Make the AHCI code find the capacity of disks > 128 GB properly Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 12/22] ahci: Use sizeof(fis) instead of hardcoding '20' Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 13/22] ahci: Fix 'Invaild' typo Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 14/22] ahci: Support 64-bit LBA option when reading capacity Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 15/22] ahci: Use virt_to_phys() to denote physical addresses for DMA Simon Glass
2012-10-29 15:23 ` [U-Boot] [PATCH v3 16/22] ahci: flush / invalidate dcache around SATA commands Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 17/22] ahci: Adjust SATA timeouts for hard disk (spinup delay & command timeout) Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 18/22] ahci: Support spin-up and link-up separately Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 19/22] ahci: Perform SATA flush after disk write Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 20/22] ahci: Expand HDD Logical Block addressability up to 32 bits Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 21/22] ide: Correct function signatures for ide_read/write() Simon Glass
2012-10-29 18:22   ` Tom Rini
2012-10-29 18:28     ` Simon Glass
2012-10-29 15:24 ` [U-Boot] [PATCH v3 22/22] x86: config: Enable AHCI support for coreboot Simon Glass
2012-11-04 18:29 ` [U-Boot] [PATCH v3 0/22] AHCI / SATA Improvements Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.