mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
ahci: Support splitting of read transactions into multiple chunks
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>
This commit is contained in:
parent
e08ebf4687
commit
284231e49a
1 changed files with 66 additions and 26 deletions
|
@ -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. */
|
||||
while (blocks) {
|
||||
u16 now_blocks; /* number of blocks per iteration */
|
||||
u32 transfer_size; /* number of bytes per iteration */
|
||||
|
||||
/* 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;
|
||||
now_blocks = min(MAX_SATA_BLOCKS_READ, blocks);
|
||||
|
||||
/* Sector Count */
|
||||
fis[12] = pccb->cmd[8];
|
||||
fis[13] = pccb->cmd[7];
|
||||
transfer_size = ATA_BLOCKSIZE * now_blocks;
|
||||
if (transfer_size > user_buffer_size) {
|
||||
printf("scsi_ahci: Error: buffer too small.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* 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;
|
||||
|
|
Loading…
Reference in a new issue