Author: mav
Date: Sat Jul 21 14:59:43 2012
New Revision: 238673
URL: http://svn.freebsd.org/changeset/base/238673

Log:
  Use 16bit PIO instead of 32bit in case of misaligned buffer.
  It fixes kernel panic during CD write with cdrecord on sparc64.

Modified:
  head/sys/dev/ata/ata-lowlevel.c

Modified: head/sys/dev/ata/ata-lowlevel.c
==============================================================================
--- head/sys/dev/ata/ata-lowlevel.c     Sat Jul 21 14:07:43 2012        
(r238672)
+++ head/sys/dev/ata/ata-lowlevel.c     Sat Jul 21 14:59:43 2012        
(r238673)
@@ -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",
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to