summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2013-05-30 01:17:38 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2013-05-30 01:17:38 +0200
commit932d5649e7402a5d46c0bdd5788b96153416af70 (patch)
treed8e6573c8ba24d565af4a2811233934ef65b8cb1
parent0bd4a8ed0ea5295bd00de63d33253ad05548d71f (diff)
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.
-rw-r--r--linux/dev/drivers/block/ahci.c44
-rw-r--r--linux/src/include/linux/hdreg.h9
2 files changed, 41 insertions, 12 deletions
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) */