ServerWorks/Broadcom HT1000 chipset errata saga

From: Travis Mikalson <bofh_at_terranova.net>
Date: Wed, 19 Dec 2007 18:06:24 -0500
As far as I can tell, Søren has the HT1000 problems worked out, or at 
least worked around. (If the chipset doesn't do that correctly, stop 
doing that...)

If you want to see the specifics, check out his commits to HEAD on 
December 13th, 2007 in src/sys/dev/ata or look at the attached patch 
which includes same.

RELENG_6 disclaimer: I haven't tried RELENG_6 with his fixes yet, and 
RELENG_6 seemed to have even stranger issues with HT1000 than RELENG_7 
did. In theory, though, this stuff should apply cleanly to RELENG_6. 
This does need testing on RELENG_6 still.

I took Søren's Dec 13th commits and made a little patchset out of it 
that applies to RELENG_7 and it has been working great for me using my 
HT1000 motherboard's on-board SATA controller.

This set of fixes should also have the similar problem with the Marvell 
chipset SATA controllers fixed, though I haven't been able to confirm 
that yet myself.

See attached patch, *please* test for RELENG_7 and report back here so 
re_at_ can feel a lot more warm and fuzzy about including this in RELENG_7 
before 7.0-RELEASE occurs.

It would be fantastic if 7.0-RELEASE worked right out of the box for 
people using HT1000-based motherboards.

Thanks,
-T
-- 
TerraNovaNet Internet Services - Key Largo, FL
Voice: (305)453-4011 x101   Fax: (305)451-5991
http://www.terranova.net/
----------------------------------------------
Life's not fair, but the root password helps.

--- src/sys/dev/ata/ata-all.h	2007/11/21 21:15:00	1.124.2.1
+++ src/sys/dev/ata/ata-all.h	2007/12/13 11:47:36	1.126
_at__at_ -464,6 +464,8 _at__at_ struct ata_lowlevel {
     int (*begin_transaction)(struct ata_request *request);
     int (*end_transaction)(struct ata_request *request);
     int (*command)(struct ata_request *request);
+    void (*tf_read)(struct ata_request *request);
+    void (*tf_write)(struct ata_request *request);
 };
 
 /* structure holding resources for an ATA channel */

--- src/sys/dev/ata/ata-chipset.c	2007/12/07 13:14:31	1.210
+++ src/sys/dev/ata/ata-chipset.c	2007/12/13 11:47:36	1.211
_at__at_ -99,7 +99,7 _at__at_ static void ata_intel_new_setmode(device
 static void ata_intel_sata_setmode(device_t dev, int mode);
 static int ata_intel_31244_allocate(device_t dev);
 static int ata_intel_31244_status(device_t dev);
-static int ata_intel_31244_command(struct ata_request *request);
+static void ata_intel_31244_tf_write(struct ata_request *request);
 static void ata_intel_31244_reset(device_t dev);
 static int ata_ite_chipinit(device_t dev);
 static void ata_ite_setmode(device_t dev, int mode);
_at__at_ -152,6 +152,8 _at__at_ static void ata_promise_queue_hpkt(struc
 static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr);
 static int ata_serverworks_chipinit(device_t dev);
 static int ata_serverworks_allocate(device_t dev);
+static void ata_serverworks_tf_read(struct ata_request *request);
+static void ata_serverworks_tf_write(struct ata_request *request);
 static void ata_serverworks_setmode(device_t dev, int mode);
 static int ata_sii_chipinit(device_t dev);
 static int ata_cmd_allocate(device_t dev);
_at__at_ -2093,7 +2095,7 _at__at_ ata_intel_31244_allocate(device_t dev)
     ch->flags |= ATA_NO_SLAVE;
     ata_pci_hw(dev);
     ch->hw.status = ata_intel_31244_status;
-    ch->hw.command = ata_intel_31244_command;
+    ch->hw.tf_write = ata_intel_31244_tf_write;
 
     /* enable PHY state change interrupt */
     ATA_OUTL(ctlr->r_res2, 0x4,
_at__at_ -2111,32 +2113,55 _at__at_ ata_intel_31244_status(device_t dev)
     return ata_pci_status(dev);
 }
 
-static int
-ata_intel_31244_command(struct ata_request *request)
+static void
+ata_intel_31244_tf_write(struct ata_request *request)
 {
     struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
     struct ata_device *atadev = device_get_softc(request->dev);
-    u_int64_t lba;
-
-    if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
-	    return (ata_generic_command(request));
-
-    lba = request->u.ata.lba;
-    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
-    /* enable interrupt */
-    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT);
-    ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
-    ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
-    ATA_IDX_OUTW(ch, ATA_SECTOR, ((lba >> 16) & 0xff00) | (lba & 0x00ff));
-    ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((lba >> 24) & 0xff00) |
-				  ((lba >> 8) & 0x00ff));
-    ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((lba >> 32) & 0xff00) | 
-				  ((lba >> 16) & 0x00ff));
 
-    /* issue command to controller */
-    ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command);
-
-    return 0;
+    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+	ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+	ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
+				      (request->u.ata.lba & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
+				       ((request->u.ata.lba >> 8) & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | 
+				       ((request->u.ata.lba >> 16) & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+    }
+    else {
+	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
+	if (atadev->flags & ATA_D_USE_CHS) {
+	    int heads, sectors;
+    
+	    if (atadev->param.atavalid & ATA_FLAG_54_58) {
+		heads = atadev->param.current_heads;
+		sectors = atadev->param.current_sectors;
+	    }
+	    else {
+		heads = atadev->param.heads;
+		sectors = atadev->param.sectors;
+	    }
+	    ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
+	    ATA_IDX_OUTB(ch, ATA_CYL_LSB,
+			 (request->u.ata.lba / (sectors * heads)));
+	    ATA_IDX_OUTB(ch, ATA_CYL_MSB,
+			 (request->u.ata.lba / (sectors * heads)) >> 8);
+	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | 
+			 (((request->u.ata.lba% (sectors * heads)) /
+			   sectors) & 0xf));
+	}
+	else {
+	    ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
+	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+	    ATA_IDX_OUTB(ch, ATA_DRIVE,
+			 ATA_D_IBM | ATA_D_LBA | atadev->unit |
+			 ((request->u.ata.lba >> 24) & 0x0f));
+	}
+    }
 }
 
 static void
_at__at_ -2849,8 +2874,12 _at__at_ ata_marvell_edma_dmainit(device_t dev)
 	/* note start and stop are not used here */
 	ch->dma->setprd = ata_marvell_edma_dmasetprd;
 	
+	/* if 64bit support present adjust max address used */
 	if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
 	    ch->dma->max_address = BUS_SPACE_MAXADDR;
+
+	/* chip does not reliably do 64K DMA transfers */
+	ch->dma->max_iosize = 126 * DEV_BSIZE; 
     }
 }
 
_at__at_ -4248,10 +4277,97 _at__at_ ata_serverworks_allocate(device_t dev)
 
     ch->flags |= ATA_NO_SLAVE;
     ata_pci_hw(dev);
+    ch->hw.tf_read = ata_serverworks_tf_read;
+    ch->hw.tf_write = ata_serverworks_tf_write;
+
+    /* chip does not reliably do 64K DMA transfers */
+    if (ch->dma)
+	ch->dma->max_iosize = 126 * DEV_BSIZE;
+
     return 0;
 }
 
 static void
+ata_serverworks_tf_read(struct ata_request *request)
+{
+    struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+    struct ata_device *atadev = device_get_softc(request->dev);
+
+    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+	u_int16_t temp;
+
+	request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT);
+	temp = ATA_IDX_INW(ch, ATA_SECTOR);
+	request->u.ata.lba = (u_int64_t)(temp & 0x00ff) |
+			     ((u_int64_t)(temp & 0xff00) << 24);
+	temp = ATA_IDX_INW(ch, ATA_CYL_LSB);
+	request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 8) |
+			      ((u_int64_t)(temp & 0xff00) << 32);
+	temp = ATA_IDX_INW(ch, ATA_CYL_MSB);
+	request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 16) |
+			      ((u_int64_t)(temp & 0xff00) << 40);
+    }
+    else {
+	request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT) & 0x00ff;
+	request->u.ata.lba = (ATA_IDX_INW(ch, ATA_SECTOR) & 0x00ff) |
+			     ((ATA_IDX_INW(ch, ATA_CYL_LSB) & 0x00ff) << 8) |
+			     ((ATA_IDX_INW(ch, ATA_CYL_MSB) & 0x00ff) << 16) |
+			     ((ATA_IDX_INW(ch, ATA_DRIVE) & 0xf) << 24);
+    }
+}
+
+static void
+ata_serverworks_tf_write(struct ata_request *request)
+{
+    struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+    struct ata_device *atadev = device_get_softc(request->dev);
+
+    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+	ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+	ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
+				      (request->u.ata.lba & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
+				       ((request->u.ata.lba >> 8) & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | 
+				       ((request->u.ata.lba >> 16) & 0x00ff));
+	ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+    }
+    else {
+	ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+	if (atadev->flags & ATA_D_USE_CHS) {
+	    int heads, sectors;
+    
+	    if (atadev->param.atavalid & ATA_FLAG_54_58) {
+		heads = atadev->param.current_heads;
+		sectors = atadev->param.current_sectors;
+	    }
+	    else {
+		heads = atadev->param.heads;
+		sectors = atadev->param.sectors;
+	    }
+	    ATA_IDX_OUTW(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
+	    ATA_IDX_OUTW(ch, ATA_CYL_LSB,
+			 (request->u.ata.lba / (sectors * heads)));
+	    ATA_IDX_OUTW(ch, ATA_CYL_MSB,
+			 (request->u.ata.lba / (sectors * heads)) >> 8);
+	    ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | 
+			 (((request->u.ata.lba% (sectors * heads)) /
+			   sectors) & 0xf));
+	}
+	else {
+	    ATA_IDX_OUTW(ch, ATA_SECTOR, request->u.ata.lba);
+	    ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+	    ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+	    ATA_IDX_OUTW(ch, ATA_DRIVE,
+			 ATA_D_IBM | ATA_D_LBA | atadev->unit |
+			 ((request->u.ata.lba >> 24) & 0x0f));
+	}
+    }
+}
+
+static void
 ata_serverworks_setmode(device_t dev, int mode)
 {
     device_t gparent = GRANDPARENT(dev);
_at__at_ -4562,7 +4678,7 _at__at_ ata_sii_allocate(device_t dev)
 
     if ((ctlr->chip->cfg2 & SIIBUG) && ch->dma) {
 	/* work around errata in early chips */
-	ch->dma->boundary = 16 * DEV_BSIZE;
+	ch->dma->boundary = 8192;
 	ch->dma->segsize = 15 * DEV_BSIZE;
     }
 
--- src/sys/dev/ata/ata-dma.c	2007/11/20 04:52:19	1.149
+++ src/sys/dev/ata/ata-dma.c	2007/12/13 11:47:36	1.150
_at__at_ -75,7 +75,7 _at__at_ ata_dmainit(device_t dev)
 	ch->dma->load = ata_dmaload;
 	ch->dma->unload = ata_dmaunload;
 	ch->dma->alignment = 2;
-	ch->dma->boundary = 128 * DEV_BSIZE;
+	ch->dma->boundary = 65536;
 	ch->dma->segsize = 128 * DEV_BSIZE;
 	ch->dma->max_iosize = 128 * DEV_BSIZE;
 	ch->dma->max_address = BUS_SPACE_MAXADDR_32BIT;

--- src/sys/dev/ata/ata-lowlevel.c	2007/04/06 16:18:59	1.79
+++ src/sys/dev/ata/ata-lowlevel.c	2007/12/13 11:47:36	1.80
_at__at_ -50,6 +50,8 _at__at_ static int ata_generic_status(device_t d
 static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t);
 static void ata_pio_read(struct ata_request *, int);
 static void ata_pio_write(struct ata_request *, int);
+static void ata_tf_read(struct ata_request *);
+static void ata_tf_write(struct ata_request *);
 
 /*
  * low level ATA functions 
_at__at_ -63,6 +65,8 _at__at_ ata_generic_hw(device_t dev)
     ch->hw.end_transaction = ata_end_transaction;
     ch->hw.status = ata_generic_status;
     ch->hw.command = ata_generic_command;
+    ch->hw.tf_read = ata_tf_read;
+    ch->hw.tf_write = ata_tf_write;
 }
 
 /* must be called with ATA channel locked and state_mtx held */
_at__at_ -244,28 +248,7 _at__at_ ata_end_transaction(struct ata_request *
 
 	/* on control commands read back registers to the request struct */
 	if (request->flags & ATA_R_CONTROL) {
-	    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
-		ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_HOB);
-		request->u.ata.count = (ATA_IDX_INB(ch, ATA_COUNT) << 8);
-		request->u.ata.lba =
-		    ((u_int64_t)(ATA_IDX_INB(ch, ATA_SECTOR)) << 24) |
-		    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_LSB)) << 32) |
-		    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_MSB)) << 40);
-
-		ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT);
-		request->u.ata.count |= ATA_IDX_INB(ch, ATA_COUNT);
-		request->u.ata.lba |= 
-		    (ATA_IDX_INB(ch, ATA_SECTOR) |
-		     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
-		     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16));
-	    }
-	    else {
-		request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT);
-		request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) |
-				     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
-				     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) |
-				     ((ATA_IDX_INB(ch, ATA_DRIVE) & 0xf) << 24);
-	    }
+	    ch->hw.tf_read(request);
 	}
 
 	/* if we got an error we are done with the HW */
_at__at_ -734,57 +717,96 _at__at_ ata_generic_command(struct ata_request *
 			   ATA_PROTO_ATAPI_12 ? 6 : 8);
     }
     else {
-	if (atadev->flags & ATA_D_48BIT_ACTIVE) {
-	    ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8);
-	    ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
-	    ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count >> 8);
-	    ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
-	    ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba >> 24);
-	    ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
-	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 32);
-	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
-	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40);
-	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
-	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
-	}
-	else {
-	    ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
-	    ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
-	    if (atadev->flags & ATA_D_USE_CHS) {
-		int heads, sectors;
+	ch->hw.tf_write(request);
+
+	/* issue command to controller */
+	ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command);
+    }
+    return 0;
+}
+
+static void
+ata_tf_read(struct ata_request *request)
+{
+    struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+    struct ata_device *atadev = device_get_softc(request->dev);
+
+    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_HOB);
+	request->u.ata.count = (ATA_IDX_INB(ch, ATA_COUNT) << 8);
+	request->u.ata.lba =
+	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_SECTOR)) << 24) |
+	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_LSB)) << 32) |
+	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_MSB)) << 40);
+
+	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT);
+	request->u.ata.count |= ATA_IDX_INB(ch, ATA_COUNT);
+	request->u.ata.lba |= 
+	    (ATA_IDX_INB(ch, ATA_SECTOR) |
+	     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
+	     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16));
+    }
+    else {
+	request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT);
+	request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) |
+			     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
+			     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) |
+			     ((ATA_IDX_INB(ch, ATA_DRIVE) & 0xf) << 24);
+    }
+}
+
+static void
+ata_tf_write(struct ata_request *request)
+{
+    struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+    struct ata_device *atadev = device_get_softc(request->dev);
+
+    if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8);
+	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count >> 8);
+	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
+	ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba >> 24);
+	ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
+	ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 32);
+	ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+	ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40);
+	ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+    }
+    else {
+	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
+	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
+	if (atadev->flags & ATA_D_USE_CHS) {
+	    int heads, sectors;
     
-		if (atadev->param.atavalid & ATA_FLAG_54_58) {
-		    heads = atadev->param.current_heads;
-		    sectors = atadev->param.current_sectors;
-		}
-		else {
-		    heads = atadev->param.heads;
-		    sectors = atadev->param.sectors;
-		}
-		ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
-		ATA_IDX_OUTB(ch, ATA_CYL_LSB,
-			     (request->u.ata.lba / (sectors * heads)));
-		ATA_IDX_OUTB(ch, ATA_CYL_MSB,
-			     (request->u.ata.lba / (sectors * heads)) >> 8);
-		ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | 
-			     (((request->u.ata.lba% (sectors * heads)) /
-			       sectors) & 0xf));
+	    if (atadev->param.atavalid & ATA_FLAG_54_58) {
+		heads = atadev->param.current_heads;
+		sectors = atadev->param.current_sectors;
 	    }
 	    else {
-		ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
-		ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
-		ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
-		ATA_IDX_OUTB(ch, ATA_DRIVE,
-			     ATA_D_IBM | ATA_D_LBA | atadev->unit |
-			     ((request->u.ata.lba >> 24) & 0x0f));
+		heads = atadev->param.heads;
+		sectors = atadev->param.sectors;
 	    }
-	}
 
-	/* issue command to controller */
-	ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command);
+	    ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
+	    ATA_IDX_OUTB(ch, ATA_CYL_LSB,
+			 (request->u.ata.lba / (sectors * heads)));
+	    ATA_IDX_OUTB(ch, ATA_CYL_MSB,
+			 (request->u.ata.lba / (sectors * heads)) >> 8);
+	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | 
+			 (((request->u.ata.lba% (sectors * heads)) /
+			   sectors) & 0xf));
+	}
+	else {
+	    ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
+	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+	    ATA_IDX_OUTB(ch, ATA_DRIVE,
+			 ATA_D_IBM | ATA_D_LBA | atadev->unit |
+			 ((request->u.ata.lba >> 24) & 0x0f));
+	}
     }
-
-    return 0;
 }
 
 static void
Received on Wed Dec 19 2007 - 22:06:26 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:24 UTC