Ignore:
Timestamp:
Jun 21, 2011, 2:39:30 PM (14 years ago)
Author:
Markus Thielen
Message:

contains CMs changes for unaligned buffers; removed unused stack var; let driver continue boot on unknown command line switch

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/os2ahci/ata.c

    r101 r110  
    3333
    3434/* -------------------------- function prototypes -------------------------- */
     35
     36static int ata_cmd_read (IORBH _far *iorb, AD_INFO *ai, int p, int d, int slot,
     37                         ULONG sector, ULONG count, SCATGATENTRY _far *sg_list,
     38                         ULONG sg_cnt);
     39
     40static int ata_cmd_write(IORBH _far *iorb, AD_INFO *ai, int p, int d, int slot,
     41                         ULONG sector, ULONG count, SCATGATENTRY _far *sg_list,
     42                         ULONG sg_cnt, int write_through);
    3543
    3644/* ------------------------ global/static variables ------------------------ */
     
    124132      if (ata_cmd.lba_l & 0xf0000000UL) {
    125133        dprintf("error: LBA-28 address %ld has more than 28 bits\n", ata_cmd.lba_l);
    126         return(-1);
     134        return(ATA_CMD_INVALID_PARM);
    127135      }
    128136      /* add upper 4 bits to device field */
     
    152160    case AP_VADDR:
    153161      /* virtual buffer address in addr/len format (up to 4K) */
    154       DevHelp_VirtToPhys(va_arg(va, void _far *), &sg_single.ppXferBuf);
     162      sg_single.ppXferBuf = virt_to_phys(va_arg(va, void _far *));
    155163      sg_single.XferBufLen = va_arg(va, u16);
    156164      sg_list = &sg_single;
     
    175183    default:
    176184      dprintf("error: v_ata_cmd() called with invalid parameter type (%d)\n", (int) ap);
    177       return(-1);
     185      return(ATA_CMD_INVALID_PARM);
    178186    }
    179187
     
    254262        return(i - 1);
    255263      }
     264      if ((sg_addr & 1) || (chunk & 1)) {
     265        ddprintf("error: ata_cmd() called with unaligned S/G element(s)\n");
     266        return(ATA_CMD_UNALIGNED_ADDR);
     267      }
    256268      cmd_tbl->sg_list[n].addr = sg_addr;
    257269      cmd_tbl->sg_list[n].size = chunk - 1;
     
    277289  }
    278290
    279   return(0);
     291  return(ATA_CMD_SUCCESS);
    280292}
    281293
     
    567579  int rc;
    568580
     581  if (io->BlockCount == 0) {
     582    /* NOP; return -1 without error in IORB to indicate success */
     583    return(-1);
     584  }
     585
     586  if (add_workspace(iorb)->unaligned) {
     587    /* unaligned S/G addresses present; need to use double buffers */
     588    return(ata_read_unaligned(iorb, slot));
     589  }
     590
    569591  /* Kludge: some I/O commands during boot use excessive S/G buffer lengths
    570592   * which cause NCQ commands to lock up. If there's only one S/G element
     
    573595   */
    574596  if (io->BlocksXferred == 0 && io->cSGList == 1 &&
    575       io->pSGList[0].XferBufLen > io->BlockCount * io->BlockSize) {
    576     io->pSGList[0].XferBufLen = io->BlockCount * io->BlockSize;
     597      io->pSGList[0].XferBufLen > (ULONG) io->BlockCount * io->BlockSize) {
     598    io->pSGList[0].XferBufLen = (ULONG) io->BlockCount * io->BlockSize;
    577599  }
    578600
     
    581603    sg_indx = ata_get_sg_indx(io);
    582604    sg_cnt = io->cSGList - sg_indx;
    583 
    584     if (sector >= (1UL << 28) || count > 256 || add_workspace(iorb)->is_ncq) {
    585       /* need LBA48 for this command */
    586       if (!ai->ports[p].devs[d].lba48) {
    587         iorb_seterr(iorb, IOERR_RBA_LIMIT);
    588         return(-1);
    589       }
    590       if (add_workspace(iorb)->is_ncq) {
    591         /* use NCQ read; count goes into feature register, tag into count! */
    592         rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ,
    593                      AP_SECTOR_48, (u32) sector, (u16) 0,
    594                      AP_FEATURES,  (u16) count,
    595                      AP_COUNT,     (u16) (slot << 3), /* tag = slot */
    596                      AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    597                      AP_DEVICE,    0x40,
    598                      AP_END);
    599       } else {
    600         rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT,
    601                      AP_SECTOR_48, (u32) sector, (u16) 0,
    602                      AP_COUNT,     (u16) count,
    603                      AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    604                      AP_DEVICE,    0x40,
    605                      AP_END);
    606       }
    607 
    608     } else {
    609       rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ,
    610                    AP_SECTOR_28, (u32) sector,
    611                    AP_COUNT,     (u16) count & 0xffU,
    612                    AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    613                    AP_DEVICE,    0x40,
    614                    AP_END);
    615     }
    616 
    617     if (rc > 0) {
     605    if ((rc = ata_cmd_read(iorb, ai, p, d, slot, sector, count,
     606                           io->pSGList + sg_indx, sg_cnt)) > 0) {
    618607      /* couldn't map all S/G elements */
    619608      ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
     
    628617    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
    629618
     619  } else if (rc == ATA_CMD_UNALIGNED_ADDR) {
     620    /* unaligned S/G addresses detected; need to use double buffers */
     621    add_workspace(iorb)->unaligned = 1;
     622    return(ata_read_unaligned(iorb, slot));
     623
     624  } else {
     625    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
     626  }
     627
     628  return(rc);
     629}
     630
     631/******************************************************************************
     632 * Read sectors from AHCI device with unaligned S/G element addresses. AHCI
     633 * only allows aligned S/G addresses while OS/2 doesn't have these kind of
     634 * restrictions. This doesn't happen very often but when it does, we need to
     635 * use a transfer buffer and copy the data manually.
     636 */
     637int ata_read_unaligned(IORBH _far *iorb, int slot)
     638{
     639  IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
     640  ADD_WORKSPACE _far *aws = add_workspace(iorb);
     641  AD_INFO *ai = ad_infos + iorb_unit_adapter(iorb);
     642  ULONG sector = io->RBA + io->BlocksXferred;
     643  SCATGATENTRY sg_single;
     644  int p = iorb_unit_port(iorb);
     645  int d = iorb_unit_device(iorb);
     646  int rc;
     647
     648  ddprintf("ata_read_unaligned(%d.%d.%d, %ld)\n", ad_no(ai), p, d, sector);
     649
     650  /* allocate transfer buffer */
     651  if ((aws->buf = malloc(io->BlockSize)) == NULL) {
     652    iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
     653    return(-1);
     654  }
     655
     656  /* prepare read command using transfer buffer */
     657  sg_single.ppXferBuf = virt_to_phys(aws->buf);
     658  sg_single.XferBufLen = io->BlockSize;
     659  rc = ata_cmd_read(iorb, ai, p, d, slot, sector, 1, &sg_single, 1);
     660
     661  if (rc == 0) {
     662    add_workspace(iorb)->blocks = 1;
     663    add_workspace(iorb)->ppfunc = ata_read_pp;
     664
     665  } else if (rc > 0) {
     666    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
     667
    630668  } else {
    631669    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
     
    638676 * Post processing function for ata_read(); this function updates the
    639677 * BlocksXferred counter in the IORB and, if not all blocks have been
    640  * transferred, requeues the IORB to process the remaining sectors.
     678 * transferred, requeues the IORB to process the remaining sectors. It also
     679 * takes care of copying data from the transfer buffer for unaligned reads.
    641680 */
    642681void ata_read_pp(IORBH _far *iorb)
    643682{
    644683  IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
     684  ADD_WORKSPACE _far *aws = add_workspace(iorb);
     685
     686  if (aws->unaligned) {
     687    /* copy transfer buffer to corresponding physical address in S/G list */
     688    sg_memcpy(io->pSGList, io->cSGList,
     689              (ULONG) io->BlocksXferred * (ULONG) io->BlockSize,
     690              aws->buf, io->BlockSize, BUF_TO_SG);
     691  }
    645692
    646693  io->BlocksXferred += add_workspace(iorb)->blocks;
     
    666713  int d = iorb_unit_device(iorb);
    667714  int rc;
     715
     716  if (io->BlockCount == 0) {
     717    /* NOP; return -1 without error in IORB to indicate success */
     718    return(-1);
     719  }
    668720
    669721  /* prepare verify command */
     
    704756  int rc;
    705757
     758  if (io->BlockCount == 0) {
     759    /* NOP; return -1 without error in IORB to indicate success */
     760    return(-1);
     761  }
     762
     763  if (add_workspace(iorb)->unaligned) {
     764    /* unaligned S/G addresses present; need to use double buffers */
     765    return(ata_write_unaligned(iorb, slot));
     766  }
     767
    706768  /* prepare write command while keeping an eye on S/G count limitations */
    707769  do {
    708770    sg_indx = ata_get_sg_indx(io);
    709771    sg_cnt = io->cSGList - sg_indx;
    710 
    711     if (sector >= (1UL << 28) || count > 256 || add_workspace(iorb)->is_ncq) {
    712       /* need LBA48 for this command */
    713       if (!ai->ports[p].devs[d].lba48) {
    714         iorb_seterr(iorb, IOERR_RBA_LIMIT);
    715         return(-1);
    716       }
    717       if (add_workspace(iorb)->is_ncq) {
    718         /* use NCQ write; count goes into feature register, tag into count! */
    719         rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE,
    720                      AP_SECTOR_48, (u32) sector, (u16) 0,
    721                      AP_FEATURES,  (u16) count,
    722                      AP_COUNT,     (u16) (slot << 3), /* tag = slot */
    723                      AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    724                      AP_DEVICE,    0x40,
    725                      AP_DEVICE,    (io->Flags & XIO_DISABLE_HW_WRITE_CACHE) ?
    726                                    0x80 : 0, /* force unit access */
    727                      AP_WRITE,     1,
    728                      AP_END);
    729       } else {
    730         rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT,
    731                      AP_SECTOR_48, (u32) sector, (u16) 0,
    732                      AP_COUNT,     (u16) count,
    733                      AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    734                      AP_DEVICE,    0x40,
    735                      AP_WRITE,     1,
    736                      AP_END);
    737       }
    738 
    739     } else {
    740       rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE,
    741                    AP_SECTOR_28, (u32) sector,
    742                    AP_COUNT,     (u16) count & 0xffU,
    743                    AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
    744                    AP_DEVICE,    0x40,
    745                    AP_WRITE,     1,
    746                    AP_END);
    747     }
    748 
    749     if (rc > 0) {
     772    if ((rc = ata_cmd_write(iorb, ai, p, d, slot, sector, count,
     773                            io->pSGList + sg_indx, sg_cnt,
     774                            io->Flags & XIO_DISABLE_HW_WRITE_CACHE)) > 0) {
    750775      /* couldn't map all S/G elements */
    751776      ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
     
    760785    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
    761786
     787  } else if (rc == ATA_CMD_UNALIGNED_ADDR) {
     788    /* unaligned S/G addresses detected; need to use double buffers */
     789    add_workspace(iorb)->unaligned = 1;
     790    return(ata_write_unaligned(iorb, slot));
     791
    762792  } else {
    763793    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
     
    766796  return(rc);
    767797}
     798
     799/******************************************************************************
     800 * Write sectors from AHCI device with unaligned S/G element addresses. AHCI
     801 * only allows aligned S/G addresses while OS/2 doesn't have these kind of
     802 * restrictions. This doesn't happen very often but when it does, we need to
     803 * use a transfer buffer and copy the data manually.
     804 */
     805int ata_write_unaligned(IORBH _far *iorb, int slot)
     806{
     807  IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
     808  ADD_WORKSPACE _far *aws = add_workspace(iorb);
     809  AD_INFO *ai = ad_infos + iorb_unit_adapter(iorb);
     810  ULONG sector = io->RBA + io->BlocksXferred;
     811  SCATGATENTRY sg_single;
     812  int p = iorb_unit_port(iorb);
     813  int d = iorb_unit_device(iorb);
     814  int rc;
     815
     816  ddprintf("ata_write_unaligned(%d.%d.%d, %ld)\n", ad_no(ai), p, d, sector);
     817
     818  /* allocate transfer buffer */
     819  if ((aws->buf = malloc(io->BlockSize)) == NULL) {
     820    iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
     821    return(-1);
     822  }
     823
     824  /* copy next sector from S/G list to transfer buffer */
     825  sg_memcpy(io->pSGList, io->cSGList,
     826            (ULONG) io->BlocksXferred * (ULONG) io->BlockSize,
     827            aws->buf, io->BlockSize, SG_TO_BUF);
     828
     829  /* prepare write command using transfer buffer */
     830  sg_single.ppXferBuf = virt_to_phys(aws->buf);
     831  sg_single.XferBufLen = io->BlockSize;
     832  rc = ata_cmd_write(iorb, ai, p, d, slot, sector, 1, &sg_single, 1,
     833                     io->Flags & XIO_DISABLE_HW_WRITE_CACHE);
     834
     835  if (rc == 0) {
     836    add_workspace(iorb)->blocks = 1;
     837    add_workspace(iorb)->ppfunc = ata_write_pp;
     838
     839  } else if (rc > 0) {
     840    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
     841
     842  } else {
     843    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
     844  }
     845
     846  return(rc);
     847}
     848
    768849
    769850/******************************************************************************
     
    888969}
    889970
     971/******************************************************************************
     972 * Fabricate ATA READ command based on the capabilities of the corresponding
     973 * device and the paramters set from above (NCQ, etc).
     974 */
     975static int ata_cmd_read(IORBH _far *iorb, AD_INFO *ai, int p, int d, int slot,
     976                        ULONG sector, ULONG count, SCATGATENTRY _far *sg_list,
     977                        ULONG sg_cnt)
     978{
     979  int rc;
     980
     981  if (sector >= (1UL << 28) || count > 256 || add_workspace(iorb)->is_ncq) {
     982    /* need LBA48 for this command */
     983    if (!ai->ports[p].devs[d].lba48) {
     984      iorb_seterr(iorb, IOERR_RBA_LIMIT);
     985      return(-1);
     986    }
     987    if (add_workspace(iorb)->is_ncq) {
     988      /* use NCQ read; count goes into feature register, tag into count! */
     989      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ,
     990                   AP_SECTOR_48, (u32) sector, (u16) 0,
     991                   AP_FEATURES,  (u16) count,
     992                   AP_COUNT,     (u16) (slot << 3), /* tag == slot */
     993                   AP_SGLIST,    sg_list, (u16) sg_cnt,
     994                   AP_DEVICE,    0x40,
     995                   AP_END);
     996    } else {
     997      rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT,
     998                   AP_SECTOR_48, (u32) sector, (u16) 0,
     999                   AP_COUNT,     (u16) count,
     1000                   AP_SGLIST,    sg_list, (u16) sg_cnt,
     1001                   AP_DEVICE,    0x40,
     1002                   AP_END);
     1003    }
     1004
     1005  } else {
     1006    rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ,
     1007                 AP_SECTOR_28, (u32) sector,
     1008                 AP_COUNT,     (u16) count & 0xffU,
     1009                 AP_SGLIST,    sg_list, (u16) sg_cnt,
     1010                 AP_DEVICE,    0x40,
     1011                 AP_END);
     1012  }
     1013 
     1014  return(rc);
     1015}
     1016
     1017/******************************************************************************
     1018 * Fabricate ATA WRITE command based on the capabilities of the corresponding
     1019 * device and the paramters set from above (NCQ, etc)
     1020 */
     1021static int ata_cmd_write(IORBH _far *iorb, AD_INFO *ai, int p, int d, int slot,
     1022                         ULONG sector, ULONG count, SCATGATENTRY _far *sg_list,
     1023                         ULONG sg_cnt, int write_through)
     1024{
     1025  int rc;
     1026
     1027  if (sector >= (1UL << 28) || count > 256 || add_workspace(iorb)->is_ncq) {
     1028    /* need LBA48 for this command */
     1029    if (!ai->ports[p].devs[d].lba48) {
     1030      iorb_seterr(iorb, IOERR_RBA_LIMIT);
     1031      return(-1);
     1032    }
     1033    if (add_workspace(iorb)->is_ncq) {
     1034      /* use NCQ write; count goes into feature register, tag into count! */
     1035      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE,
     1036                   AP_SECTOR_48, (u32) sector, (u16) 0,
     1037                   AP_FEATURES,  (u16) count,
     1038                   AP_COUNT,     (u16) (slot << 3), /* tag = slot */
     1039                   AP_SGLIST,    sg_list, (u16) sg_cnt,
     1040                   AP_DEVICE,    0x40,
     1041                   AP_DEVICE,    (write_through) ? 0x80 : 0, /* force unit access */
     1042                   AP_WRITE,     1,
     1043                   AP_END);
     1044    } else {
     1045      rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT,
     1046                   AP_SECTOR_48, (u32) sector, (u16) 0,
     1047                   AP_COUNT,     (u16) count,
     1048                   AP_SGLIST,    sg_list, (u16) sg_cnt,
     1049                   AP_DEVICE,    0x40,
     1050                   AP_WRITE,     1,
     1051                   AP_END);
     1052    }
     1053
     1054  } else {
     1055    rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE,
     1056                 AP_SECTOR_28, (u32) sector,
     1057                 AP_COUNT,     (u16) count & 0xffU,
     1058                 AP_SGLIST,    sg_list, (u16) sg_cnt,
     1059                 AP_DEVICE,    0x40,
     1060                 AP_WRITE,     1,
     1061                 AP_END);
     1062  }
     1063
     1064  return(rc);
     1065}
Note: See TracChangeset for help on using the changeset viewer.