From: Jens Axboe <axboe@suse.de>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] lba48 support
Date: Thu, 29 Dec 2005 23:07:52 +0100 [thread overview]
Message-ID: <20051229220752.GP2772@suse.de> (raw)
Hi,
Saw the posts on this the other day and had a few spare hours to play
with this. Works for me, with and without DMA (didn't test mult mode,
but that should work fine too).
Test with caution though, it's changing the ide code so could eat your
data if there's a bug there... Most clever OS's don't use lba48 even for
lba48 capable drives, unless the device is > 2^28 sectors and the
current request is past that (but they could be taking advantage of the
larger transfer size possible, in which case lba48 will be used even for
low sectors...).
Index: hw/ide.c
===================================================================
RCS file: /sources/qemu/qemu/hw/ide.c,v
retrieving revision 1.38
diff -u -r1.38 ide.c
--- hw/ide.c 6 Aug 2005 09:14:32 -0000 1.38
+++ hw/ide.c 29 Dec 2005 22:05:18 -0000
@@ -305,14 +305,26 @@
/* ide regs */
uint8_t feature;
uint8_t error;
- uint16_t nsector; /* 0 is 256 to ease computations */
+ uint32_t nsector;
uint8_t sector;
uint8_t lcyl;
uint8_t hcyl;
+ /* other part of tf for lba48 support */
+ uint8_t hob_feature;
+ uint8_t hob_nsector;
+ uint8_t hob_sector;
+ uint8_t hob_lcyl;
+ uint8_t hob_hcyl;
+
uint8_t select;
uint8_t status;
+
/* 0x3f6 command, only meaningful for drive 0 */
uint8_t cmd;
+ /* keeping track of registers written before command, for the hob part */
+ uint8_t regs_written;
+ /* set for lba48 access */
+ uint8_t lba48;
/* depends on bit 4 in select, only meaningful for drive 0 */
struct IDEState *cur_drive;
BlockDriverState *bs;
@@ -449,13 +461,17 @@
put_le16(p + 61, s->nb_sectors >> 16);
put_le16(p + 80, (1 << 1) | (1 << 2));
put_le16(p + 82, (1 << 14));
- put_le16(p + 83, (1 << 14));
+ put_le16(p + 83, (1 << 14) | (1 << 10)); /* lba48 supported */
put_le16(p + 84, (1 << 14));
put_le16(p + 85, (1 << 14));
- put_le16(p + 86, 0);
+ put_le16(p + 86, (1 << 14) | (1 << 10)); /* lba48 supported */
put_le16(p + 87, (1 << 14));
put_le16(p + 88, 0x1f | (1 << 13));
put_le16(p + 93, 1 | (1 << 14) | 0x2000 | 0x4000);
+ put_le16(p + 100, s->nb_sectors);
+ put_le16(p + 101, s->nb_sectors >> 16);
+ put_le16(p + 102, s->nb_sectors >> 32);
+ put_le16(p + 103, s->nb_sectors >> 48);
}
static void ide_atapi_identify(IDEState *s)
@@ -548,12 +564,18 @@
int64_t sector_num;
if (s->select & 0x40) {
/* lba */
- sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
- (s->lcyl << 8) | s->sector;
+ if (!s->lba48) {
+ sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
+ (s->lcyl << 8) | s->sector;
+ } else {
+ sector_num = ((int64_t)s->hcyl << 40) |
+ ((int64_t) s->lcyl << 32) |
+ (s->sector << 24) | (s->hob_hcyl << 16) |
+ (s->hob_lcyl << 8) | s->hob_sector;
+ }
} else {
sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
- (s->select & 0x0f) * s->sectors +
- (s->sector - 1);
+ (s->select & 0x0f) * s->sectors + (s->sector - 1);
}
return sector_num;
}
@@ -562,10 +584,19 @@
{
unsigned int cyl, r;
if (s->select & 0x40) {
- s->select = (s->select & 0xf0) | (sector_num >> 24);
- s->hcyl = (sector_num >> 16);
- s->lcyl = (sector_num >> 8);
- s->sector = (sector_num);
+ if (!s->lba48) {
+ s->select = (s->select & 0xf0) | (sector_num >> 24);
+ s->hcyl = (sector_num >> 16);
+ s->lcyl = (sector_num >> 8);
+ s->sector = (sector_num);
+ } else {
+ s->hob_sector = sector_num;
+ s->hob_lcyl = sector_num >> 8;
+ s->hob_hcyl = sector_num >> 16;
+ s->sector = sector_num >> 24;
+ s->lcyl = sector_num >> 32;
+ s->hcyl = sector_num >> 40;
+ }
} else {
cyl = sector_num / (s->heads * s->sectors);
r = sector_num % (s->heads * s->sectors);
@@ -1455,37 +1486,64 @@
{
IDEState *ide_if = opaque;
IDEState *s;
- int unit, n;
+ int unit, n, hob = 0, lba48_cmd = 0;
#ifdef DEBUG_IDE
printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
#endif
addr &= 7;
+ if (addr >= 1 && addr <= 5) {
+ ide_if[0].regs_written |= (1 << addr);
+ hob = ((ide_if[0].regs_written & 0x3e) == 0x3e);
+ }
switch(addr) {
case 0:
break;
case 1:
/* NOTE: data is written to the two drives */
- ide_if[0].feature = val;
- ide_if[1].feature = val;
+ if (!hob) {
+ ide_if[0].feature = val;
+ ide_if[1].feature = val;
+ } else {
+ ide_if[0].hob_feature = val;
+ ide_if[1].hob_feature = val;
+ }
break;
case 2:
- if (val == 0)
- val = 256;
- ide_if[0].nsector = val;
- ide_if[1].nsector = val;
+ if (!hob) {
+ ide_if[0].nsector = val;
+ ide_if[1].nsector = val;
+ } else {
+ ide_if[0].hob_nsector = val;
+ ide_if[1].hob_nsector = val;
+ }
break;
case 3:
- ide_if[0].sector = val;
- ide_if[1].sector = val;
+ if (!hob) {
+ ide_if[0].sector = val;
+ ide_if[1].sector = val;
+ } else {
+ ide_if[0].hob_sector = val;
+ ide_if[1].hob_sector = val;
+ }
break;
case 4:
- ide_if[0].lcyl = val;
- ide_if[1].lcyl = val;
+ if (!hob) {
+ ide_if[0].lcyl = val;
+ ide_if[1].lcyl = val;
+ } else {
+ ide_if[0].hob_lcyl = val;
+ ide_if[1].hob_lcyl = val;
+ }
break;
case 5:
- ide_if[0].hcyl = val;
- ide_if[1].hcyl = val;
+ if (!hob) {
+ ide_if[0].hcyl = val;
+ ide_if[1].hcyl = val;
+ } else {
+ ide_if[0].hob_hcyl = val;
+ ide_if[1].hob_hcyl = val;
+ }
break;
case 6:
ide_if[0].select = (val & ~0x10) | 0xa0;
@@ -1501,10 +1559,34 @@
#if defined(DEBUG_IDE)
printf("ide: CMD=%02x\n", val);
#endif
+ /* clear regs written when we see any command */
+ ide_if[0].regs_written = 0;
+
s = ide_if->cur_drive;
/* ignore commands to non existant slave */
if (s != ide_if && !s->bs)
break;
+
+ s->lba48 = lba48_cmd;
+
+ /* handle the 'magic' 0 nsector count conversion here. to avoid
+ * fiddling with the rest of the read logic, we just store the
+ * full sector count in ->nsector and ignore ->hob_nsector from now
+ */
+ if (!s->lba48) {
+ if (!s->nsector)
+ s->nsector = 256;
+ } else {
+ if (!s->nsector && !s->hob_nsector)
+ s->nsector = 65536;
+ else {
+ int lo = s->hob_nsector;
+ int hi = s->nsector;
+
+ s->nsector = (hi << 8) | lo;
+ }
+ }
+
switch(val) {
case WIN_IDENTIFY:
if (s->bs && !s->is_cdrom) {
@@ -1536,12 +1618,16 @@
}
ide_set_irq(s);
break;
+ case WIN_VERIFY_EXT:
+ lba48_cmd = 1;
case WIN_VERIFY:
case WIN_VERIFY_ONCE:
/* do sector number check ? */
s->status = READY_STAT;
ide_set_irq(s);
break;
+ case WIN_READ_EXT:
+ lba48_cmd = 1;
case WIN_READ:
case WIN_READ_ONCE:
if (!s->bs)
@@ -1549,6 +1635,8 @@
s->req_nb_sectors = 1;
ide_sector_read(s);
break;
+ case WIN_WRITE_EXT:
+ lba48_cmd = 1;
case WIN_WRITE:
case WIN_WRITE_ONCE:
s->error = 0;
@@ -1556,12 +1644,16 @@
s->req_nb_sectors = 1;
ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
break;
+ case WIN_MULTREAD_EXT:
+ lba48_cmd = 1;
case WIN_MULTREAD:
if (!s->mult_sectors)
goto abort_cmd;
s->req_nb_sectors = s->mult_sectors;
ide_sector_read(s);
break;
+ case WIN_MULTWRITE_EXT:
+ lba48_cmd = 1;
case WIN_MULTWRITE:
if (!s->mult_sectors)
goto abort_cmd;
@@ -1573,18 +1665,24 @@
n = s->req_nb_sectors;
ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
break;
+ case WIN_READDMA_EXT:
+ lba48_cmd = 1;
case WIN_READDMA:
case WIN_READDMA_ONCE:
if (!s->bs)
goto abort_cmd;
ide_sector_read_dma(s);
break;
+ case WIN_WRITEDMA_EXT:
+ lba48_cmd = 1;
case WIN_WRITEDMA:
case WIN_WRITEDMA_ONCE:
if (!s->bs)
goto abort_cmd;
ide_sector_write_dma(s);
break;
+ case WIN_READ_NATIVE_MAX_EXT:
+ lba48_cmd = 1;
case WIN_READ_NATIVE_MAX:
ide_set_sector(s, s->nb_sectors - 1);
s->status = READY_STAT;
@@ -1615,6 +1713,7 @@
case WIN_STANDBYNOW1:
case WIN_IDLEIMMEDIATE:
case WIN_FLUSH_CACHE:
+ case WIN_FLUSH_CACHE_EXT:
s->status = READY_STAT;
ide_set_irq(s);
break;
--
Jens Axboe
next reply other threads:[~2005-12-29 22:07 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-12-29 22:07 Jens Axboe [this message]
2005-12-30 22:14 ` [Qemu-devel] [PATCH] lba48 support Fabrice Bellard
2005-12-30 20:17 ` Jens Axboe
2006-01-02 12:59 ` Jens Axboe
2006-01-02 15:20 ` Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20051229220752.GP2772@suse.de \
--to=axboe@suse.de \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.