From 932d5649e7402a5d46c0bdd5788b96153416af70 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Thu, 30 May 2013 01:17:38 +0200 Subject: Add LBA48 support to AHCI driver * linux/dev/drivers/block/ahci.c (port): Extend `capacity' field type to unsigned long long. Add `lba48' field. Make `identify' field unsigned. (ahci_do_port_request): When `lba48' is true, use WIN_READDMA_EXT and WIN_WRITEDMA_EXT commands. (ahci_probe_port): Test lba48 flag, read capacity and set `lba48' accordingly. Display size in GiB above 10GiB. * linux/src/include/linux/hdreg.h (WIN_READDMA_EXT, WIN_WRITEDMA_EXT): New macros (hd_driveid): Add `command_set_2' and lba_capacity_2' fields. --- linux/dev/drivers/block/ahci.c | 44 ++++++++++++++++++++++++++++++++++------- linux/src/include/linux/hdreg.h | 9 ++++----- 2 files changed, 41 insertions(+), 12 deletions(-) (limited to 'linux') diff --git a/linux/dev/drivers/block/ahci.c b/linux/dev/drivers/block/ahci.c index 0ea1e3e..3b31e84 100644 --- a/linux/dev/drivers/block/ahci.c +++ b/linux/dev/drivers/block/ahci.c @@ -239,13 +239,14 @@ static struct port { struct ahci_fis *fis; struct ahci_cmd_tbl *prdtl; - unsigned capacity; /* Nr of sectors */ + unsigned long long capacity; /* Nr of sectors */ u32 status; /* interrupt status */ unsigned cls; /* Command list maximum size. We currently only use 1. */ struct wait_queue *q; /* IRQ wait queue */ struct hd_struct *part; /* drive partition table */ - int identify; /* Whether we are just identifying + unsigned lba48; /* Whether LBA48 is supported */ + unsigned identify; /* Whether we are just identifying at boot */ } ports[MAX_PORTS]; @@ -301,10 +302,16 @@ static void ahci_do_port_request(struct port *port, unsigned sector, struct requ fis_h2d = (void*) &prdtl[slot].cfis; fis_h2d->fis_type = FIS_TYPE_REG_H2D; fis_h2d->flags = 128; - if (rq->cmd == READ) - fis_h2d->command = WIN_READDMA; + if (port->lba48) + if (rq->cmd == READ) + fis_h2d->command = WIN_READDMA_EXT; + else + fis_h2d->command = WIN_WRITEDMA_EXT; else - fis_h2d->command = WIN_WRITEDMA; + if (rq->cmd == READ) + fis_h2d->command = WIN_READDMA; + else + fis_h2d->command = WIN_WRITEDMA; fis_h2d->device = 1<<6; /* LBA */ @@ -679,12 +686,35 @@ static void ahci_probe_port(const volatile struct ahci_host *ahci_host, const vo { printk("sd%u: identify error\n", port-ports); port->capacity = 0; + port->lba48 = 0; } else { ide_fixstring(id.model, sizeof(id.model), 1); ide_fixstring(id.fw_rev, sizeof(id.fw_rev), 1); ide_fixstring(id.serial_no, sizeof(id.serial_no), 1); - port->capacity = id.lba_capacity; - printk("sd%u: %s, %uMB w/%dkB Cache\n", port - ports, id.model, port->capacity/2048, id.buf_size/2); + if (id.command_set_2 & (1U<<10)) + { + port->lba48 = 1; + port->capacity = id.lba_capacity_2; + if (port->capacity >= (1ULL << 32)) + { + port->capacity = (1ULL << 32) - 1; + printk("Warning: truncating disk size to 2TiB\n"); + } + } + else + { + port->lba48 = 0; + port->capacity = id.lba_capacity; + if (port->capacity > (1ULL << 24)) + { + port->capacity = (1ULL << 24); + printk("Warning: truncating disk size to 128GiB\n"); + } + } + if (port->capacity/2048 >= 10240) + printk("sd%u: %s, %uGB w/%dkB Cache\n", port - ports, id.model, port->capacity/(2048*1024), id.buf_size/2); + else + printk("sd%u: %s, %uMB w/%dkB Cache\n", port - ports, id.model, port->capacity/2048, id.buf_size/2); } port->identify = 0; } diff --git a/linux/src/include/linux/hdreg.h b/linux/src/include/linux/hdreg.h index e223480..4a388c5 100644 --- a/linux/src/include/linux/hdreg.h +++ b/linux/src/include/linux/hdreg.h @@ -62,6 +62,8 @@ #define WIN_SETFEATURES 0xEF /* set special drive features */ #define WIN_READDMA 0xc8 /* read sectors using DMA transfers */ #define WIN_WRITEDMA 0xca /* write sectors using DMA transfers */ +#define WIN_READDMA_EXT 0x25 /* read sectors using LBA48 DMA transfers */ +#define WIN_WRITEDMA_EXT 0x35 /* write sectors using LBA48 DMA transfers */ /* Additional drive command codes used by ATAPI devices. */ #define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ @@ -168,7 +170,7 @@ struct hd_driveid { unsigned short word80; unsigned short word81; unsigned short command_sets; /* bits 0:Smart 1:Security 2:Removable 3:PM */ - unsigned short word83; /* bits 14:Smart Enabled 13:0 zero */ + unsigned short command_set_2; /* bits 14:Smart Enabled 13:0 zero */ unsigned short word84; unsigned short word85; unsigned short word86; @@ -185,10 +187,7 @@ struct hd_driveid { unsigned short word97; /* reserved (word 97) */ unsigned short word98; /* reserved (word 98) */ unsigned short word99; /* reserved (word 99) */ - unsigned short word100; /* reserved (word 100) */ - unsigned short word101; /* reserved (word 101) */ - unsigned short word102; /* reserved (word 102) */ - unsigned short word103; /* reserved (word 103) */ + unsigned long long lba_capacity_2; /* 48-bit total number of sectors */ unsigned short word104; /* reserved (word 104) */ unsigned short word105; /* reserved (word 105) */ unsigned short word106; /* reserved (word 106) */ -- cgit v1.2.3