summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-07-21 14:59:43 +0000
committermav <mav@FreeBSD.org>2012-07-21 14:59:43 +0000
commit5793dc999474e150f00abc0222b1fe04f86586b0 (patch)
treeb5cdb56ed8f6362e59548c930870c3880107a3da
parent5de732736277b342776f68948e77edd33c37779b (diff)
downloadFreeBSD-src-5793dc999474e150f00abc0222b1fe04f86586b0.zip
FreeBSD-src-5793dc999474e150f00abc0222b1fe04f86586b0.tar.gz
Use 16bit PIO instead of 32bit in case of misaligned buffer.
It fixes kernel panic during CD write with cdrecord on sparc64.
-rw-r--r--sys/dev/ata/ata-lowlevel.c32
1 files changed, 14 insertions, 18 deletions
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
index 42dbf87..e6522c6 100644
--- a/sys/dev/ata/ata-lowlevel.c
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -836,23 +836,21 @@ static void
ata_pio_read(struct ata_request *request, int length)
{
struct ata_channel *ch = device_get_softc(request->parent);
+ uint8_t *addr;
int size = min(request->transfersize, length);
int resid;
uint8_t buf[2];
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) {
- ATA_IDX_INSW_STRM(ch, ATA_DATA,
- (void*)((uintptr_t)request->data+request->donecount),
- size / sizeof(int16_t));
+ addr = (uint8_t *)request->data + request->donecount;
+ if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)) ||
+ ((uintptr_t)addr % sizeof(int32_t))) {
+ ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int16_t));
if (size & 1) {
ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)buf, 1);
- ((uint8_t *)request->data + request->donecount +
- (size & ~1))[0] = buf[0];
+ (addr + (size & ~1))[0] = buf[0];
}
} else
- ATA_IDX_INSL_STRM(ch, ATA_DATA,
- (void*)((uintptr_t)request->data+request->donecount),
- size / sizeof(int32_t));
+ ATA_IDX_INSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t));
if (request->transfersize < length) {
device_printf(request->parent, "WARNING - %s read data overrun %d>%d\n",
@@ -867,23 +865,21 @@ static void
ata_pio_write(struct ata_request *request, int length)
{
struct ata_channel *ch = device_get_softc(request->parent);
+ uint8_t *addr;
int size = min(request->transfersize, length);
int resid;
uint8_t buf[2];
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) {
- ATA_IDX_OUTSW_STRM(ch, ATA_DATA,
- (void*)((uintptr_t)request->data+request->donecount),
- size / sizeof(int16_t));
+ addr = (uint8_t *)request->data + request->donecount;
+ if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)) ||
+ ((uintptr_t)addr % sizeof(int32_t))) {
+ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int16_t));
if (size & 1) {
- buf[0] = ((uint8_t *)request->data + request->donecount +
- (size & ~1))[0];
+ buf[0] = (addr + (size & ~1))[0];
ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)buf, 1);
}
} else
- ATA_IDX_OUTSL_STRM(ch, ATA_DATA,
- (void*)((uintptr_t)request->data+request->donecount),
- size / sizeof(int32_t));
+ ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t));
if (request->transfersize < length) {
device_printf(request->parent, "WARNING - %s write data underrun %d>%d\n",
OpenPOWER on IntegriCloud