Changeset 207 for trunk/src/os2ahci/ata.c
- Timestamp:
- Feb 23, 2021, 10:10:11 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/os2ahci/ata.c
r205 r207 26 26 */ 27 27 28 #define INCL_LONGLONG 28 29 #include "os2ahci.h" 29 30 #include "ata.h" 30 31 31 /* -------------------------- function prototypes -------------------------- */ 32 33 static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot, 34 ULONG sector, ULONG count, SCATGATENTRY *sg_list, 35 ULONG sg_cnt); 36 37 static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot, 38 ULONG sector, ULONG count, SCATGATENTRY *sg_list, 39 ULONG sg_cnt, int write_through); 32 #define MAKEULL(h,l) (((ULONGLONG)h<<32)|l) 40 33 41 34 /****************************************************************************** … … 256 249 { 257 250 u32 chunk = (sg_size > AHCI_MAX_SG_ELEMENT_LEN) ? AHCI_MAX_SG_ELEMENT_LEN : sg_size; 251 258 252 if (n >= AHCI_MAX_SG) 259 253 { 260 254 /* couldn't store all S/G elements in our DMA buffer */ 261 dprintf(0,"ata_cmd(): too many S/G elements\n"); 255 if (sg_size) 256 { 257 dprintf(0, __func__": unaligned SG element\n"); 258 return -1; 259 } 260 dprintf(0, __func__": too many S/G elements\n"); 262 261 return(i - 1); 263 262 } … … 341 340 342 341 /****************************************************************************** 343 * Get index in S/G list for the number of transferred sectors in the IORB.344 *345 * Returning io->cSGList indicates an error.346 *347 * NOTE: OS/2 makes sure S/G lists are set up such that entries at the HW348 * limit will never cross sector boundaries. This means that splitting349 * S/G lists into multiple commands can be done without editing the S/G350 * lists.351 */352 u16 ata_get_sg_indx(IORB_EXECUTEIO *io)353 {354 ULONG offset = io->BlocksXferred * io->BlockSize;355 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);356 USHORT i;357 358 for (i = 0; i < io->cSGList && offset > 0; i++)359 {360 offset -= pSGList[i].XferBufLen;361 }362 363 return(i);364 }365 366 /******************************************************************************367 342 * Get max S/G count which will fit into our HW S/G buffers. This function is 368 343 * called when the S/G list is too long and we need to split the IORB into … … 459 434 * geometry to the last full cylinder. 460 435 */ 461 int adjust_cylinders(GEOMETRY *geometry, ULONG TotalSectors)436 int adjust_cylinders(GEOMETRY64 *geometry, ULONG TotalSectors) 462 437 { 463 438 USHORT SecPerCyl; … … 487 462 #define BIOS_MAX_NUMHEADS 255 488 463 #define BIOS_MAX_SECTORSPERTRACK 63 489 void log_geom_calculate_LBA_assist(GEOMETRY *geometry, ULONG TotalSectors)464 void log_geom_calculate_LBA_assist(GEOMETRY64 *geometry, ULONG TotalSectors) 490 465 { 491 466 UCHAR numSpT = BIOS_MAX_SECTORSPERTRACK; … … 524 499 DLA_Table_Sector *pDLA = (DLA_Table_Sector*)add_workspace(pIorb)->buf; 525 500 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb); 526 GEOMETRY *geometry =((IORB_GEOMETRY*)pIorb)->f16Geometry;501 GEOMETRY64 *geometry = (GEOMETRY64*)((IORB_GEOMETRY*)pIorb)->f16Geometry; 527 502 int p = iorb_unit_port(pIorb); 528 503 int rc; … … 544 519 geometry->NumHeads = pDLA->Heads_Per_Cylinder; 545 520 geometry->SectorsPerTrack = pDLA->Sectors_Per_Track; 546 geometry->TotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track; 521 if (add_workspace(pIorb)->fIs64bit) 522 geometry->ullTotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track; 523 else 524 geometry->TotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track; 547 525 return 1; 548 526 } … … 589 567 void ata_get_geometry_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb) 590 568 { 591 GEOMETRY *geometry =((IORB_GEOMETRY*)pIorb)->f16Geometry;569 GEOMETRY64 *geometry = (GEOMETRY64*)((IORB_GEOMETRY*)pIorb)->f16Geometry; 592 570 USHORT geometry_len = ((IORB_GEOMETRY *)pIorb)->GeometryLen; 571 ULONGLONG ullTotalSectors; 593 572 u16 *id_buf = add_workspace(pIorb)->buf; 594 573 int a = iorb_unit_adapter(pIorb); … … 627 606 * can be unexpected and catastrophic. 628 607 */ 629 memset(geometry, 0 x00, geometry_len);608 memset(geometry, 0, geometry_len); 630 609 geometry->BytesPerSector = ATA_SECTOR_SIZE; 631 610 … … 634 613 { 635 614 /* 48-bit LBA supported */ 636 if ( ATA_CAPACITY48_H(id_buf) != 0)615 if ((ATA_CAPACITY48_H(id_buf) != 0) && !add_workspace(pIorb)->fIs64bit) 637 616 { 638 617 /* more than 32 bits for number of sectors */ … … 640 619 iorb_unit_adapter(pIorb), iorb_unit_port(pIorb), 641 620 iorb_unit_device(pIorb)); 642 geometry->TotalSectors = 0xffffffffUL;621 ullTotalSectors = 0xffffffff; 643 622 } 644 623 else 645 624 { 646 geometry->TotalSectors = ATA_CAPACITY48_L(id_buf);625 ullTotalSectors = MAKEULL(ATA_CAPACITY48_H(id_buf), ATA_CAPACITY48_L(id_buf)); 647 626 } 648 627 } … … 650 629 { 651 630 /* 28-bit LBA */ 652 geometry->TotalSectors = ATA_CAPACITY(id_buf) & 0x0fffffffUL;631 ullTotalSectors = ATA_CAPACITY(id_buf) & 0x0fffffff; 653 632 } 654 633 … … 663 642 geometry->NumHeads = 255; 664 643 geometry->SectorsPerTrack = track_size[a][p]; 665 geometry->TotalCylinders = geometry->TotalSectors / ((u32) geometry->NumHeads * (u32)geometry->SectorsPerTrack);644 geometry->TotalCylinders = ullTotalSectors / ((u32)geometry->NumHeads * (u32)geometry->SectorsPerTrack); 666 645 Method = "Custom"; 667 646 } … … 688 667 geometry->NumHeads = 255; 689 668 geometry->SectorsPerTrack = 63; 690 geometry->TotalCylinders = geometry->TotalSectors / ((u32) geometry->NumHeads * (u32)geometry->SectorsPerTrack);669 geometry->TotalCylinders = ullTotalSectors / ((u32)geometry->NumHeads * (u32)geometry->SectorsPerTrack); 691 670 Method = "SCSI"; 692 671 } … … 694 673 DPRINTF(2,"Physical geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n", 695 674 geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack, 696 (geometry->TotalSectors / 2048), Method); 697 698 /* Fixup the geometry in case the geometry reported by the BIOS is bad */ 699 if (adjust_cylinders(geometry, geometry->TotalSectors)) 700 { // cylinder overflow 701 log_geom_calculate_LBA_assist(geometry, geometry->TotalSectors); 702 geometry->TotalSectors = (USHORT)(geometry->NumHeads * geometry->SectorsPerTrack) * (ULONG)geometry->TotalCylinders; 703 } 704 adjust_cylinders(geometry, geometry->TotalSectors); 705 706 DPRINTF(2,"Logical geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n", 707 geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack, 708 (geometry->TotalSectors / 2048), Method); 709 710 if (is_lvm_geometry(pIorb)) Method = "LVM"; 675 (ULONG)(ullTotalSectors / 2048), Method); 676 677 if (is_lvm_geometry(pIorb)) Method = "LVM"; /* Writes TotalSectors/ullTotalSectors */ 678 else 679 { 680 if (add_workspace(pIorb)->fIs64bit) 681 { 682 geometry->NumHeads = 255; 683 geometry->SectorsPerTrack = 255; 684 geometry->TotalCylinders = ullTotalSectors / (255*255); 685 geometry->ullTotalSectors = ullTotalSectors; 686 } 687 else 688 { 689 /* Fixup the geometry in case the geometry reported by the BIOS is bad */ 690 if (adjust_cylinders(geometry, ullTotalSectors)) /* Writes TotalSectors */ 691 { // cylinder overflow 692 log_geom_calculate_LBA_assist(geometry, ullTotalSectors); /* Does not write TotalSectors */ 693 ullTotalSectors = (USHORT)(geometry->NumHeads * geometry->SectorsPerTrack) * (ULONG)geometry->TotalCylinders; 694 } 695 adjust_cylinders(geometry, ullTotalSectors); /* Writes TotalSectors */ 696 } 697 } 698 if (add_workspace(pIorb)->fIs64bit) ullTotalSectors = geometry->ullTotalSectors; 699 else ullTotalSectors = geometry->TotalSectors; 700 711 701 ad_infos[a].ports[p].devs[0].dev_info.Cylinders = geometry->TotalCylinders; 712 702 ad_infos[a].ports[p].devs[0].dev_info.HeadsPerCylinder = geometry->NumHeads; 713 703 ad_infos[a].ports[p].devs[0].dev_info.SectorsPerTrack = geometry->SectorsPerTrack; 714 ad_infos[a].ports[p].devs[0].dev_info.TotalSectors = geometry->TotalSectors;704 ad_infos[a].ports[p].devs[0].dev_info.TotalSectors = ullTotalSectors; 715 705 ad_infos[a].ports[p].devs[0].dev_info.Method = Method; 716 706 717 DPRINTF(2,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n", 707 //DAZ DPRINTF(2,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n", 708 DPRINTF(0,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n", 718 709 geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack, 719 ( geometry->TotalSectors / 2048), Method);710 (ULONG)(ullTotalSectors / 2048), Method); 720 711 721 712 /* tell interrupt handler that this IORB is complete */ … … 737 728 738 729 /****************************************************************************** 730 * Fabricate ATA READ command based on the capabilities of the corresponding 731 * device and the paramters set from above (NCQ, etc). 732 */ 733 static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot, 734 ULONGLONG ullLba, ULONG count, SCATGATENTRY *sg_list, 735 ULONG sg_cnt) 736 { 737 int rc; 738 739 if (ullLba >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq) 740 { 741 /* need LBA48 for this command */ 742 if (!ai->ports[p].devs[d].lba48) 743 { 744 iorb_seterr(pIorb, IOERR_RBA_LIMIT); 745 return(-1); 746 } 747 if (add_workspace(pIorb)->is_ncq) 748 { 749 /* use NCQ read; count goes into feature register, tag into count! */ 750 rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ, 751 AP_SECTOR_48, ullLba, 752 AP_FEATURES, count, 753 AP_COUNT, (slot << 3), /* tag == slot */ 754 AP_SGLIST, sg_list, sg_cnt, 755 AP_DEVICE, 0x40, 756 AP_END); 757 } 758 else 759 { 760 rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT, 761 AP_SECTOR_48, ullLba, 762 AP_COUNT, count, 763 AP_SGLIST, sg_list, sg_cnt, 764 AP_DEVICE, 0x40, 765 AP_END); 766 } 767 768 } 769 else 770 { 771 rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ, 772 AP_SECTOR_28, (ULONG)ullLba, 773 AP_COUNT, count & 0xffU, 774 AP_SGLIST, sg_list, sg_cnt, 775 AP_DEVICE, 0x40, 776 AP_END); 777 } 778 779 return(rc); 780 } 781 782 /****************************************************************************** 739 783 * Read sectors from AHCI device. 740 784 */ … … 744 788 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList); 745 789 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb); 746 ULONG sector= io->RBA + io->BlocksXferred;790 ULONGLONG ullLba = io->RBA + io->BlocksXferred; 747 791 USHORT count = io->BlockCount - io->BlocksXferred; 748 792 USHORT sg_indx; … … 762 806 /* unaligned S/G addresses present; need to use double buffers */ 763 807 return(ata_read_unaligned(pIorb, slot)); 808 } 809 810 if (add_workspace(pIorb)->fIs64bit) 811 { 812 ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred; 764 813 } 765 814 … … 778 827 do 779 828 { 780 sg_indx = ata_get_sg_indx(io);829 sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize); 781 830 sg_cnt = io->cSGList - sg_indx; 782 if ((rc = ata_cmd_read(pIorb, ai, p, d, slot, sector, count,783 pSGList + sg_indx, sg_cnt))> 0)831 rc = ata_cmd_read(pIorb, ai, p, d, slot, ullLba, count, pSGList + sg_indx, sg_cnt); 832 if (rc > 0) 784 833 { 785 834 /* couldn't map all S/G elements */ … … 802 851 add_workspace(pIorb)->unaligned = 1; 803 852 return(ata_read_unaligned(pIorb, slot)); 804 805 853 } 806 854 else … … 823 871 ADD_WORKSPACE *aws = add_workspace(pIorb); 824 872 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb); 825 ULONG sector= io->RBA + io->BlocksXferred;873 ULONGLONG ullLba = io->RBA + io->BlocksXferred; 826 874 SCATGATENTRY sg_single; 827 875 int p = iorb_unit_port(pIorb); … … 829 877 int rc; 830 878 831 DPRINTF(7,"ata_read_unaligned(%d.%d.%d, %d)\n", ad_no(ai), p, d, sector); 879 if (add_workspace(pIorb)->fIs64bit) 880 { 881 ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred; 882 } 883 884 DPRINTF(7,"ata_read_unaligned(%d.%d.%d, %lld)\n", ad_no(ai), p, d, ullLba); 832 885 ai->ports[p].unaligned_read_count++; 833 886 … … 842 895 sg_single.ppXferBuf = MemPhysAdr(aws->buf); 843 896 sg_single.XferBufLen = io->BlockSize; 844 rc = ata_cmd_read(pIorb, ai, p, d, slot, sector, 1, &sg_single, 1);897 rc = ata_cmd_read(pIorb, ai, p, d, slot, ullLba, 1, &sg_single, 1); 845 898 846 899 if (rc == 0) { … … 873 926 { 874 927 /* copy transfer buffer to corresponding physical address in S/G list */ 875 sg_memcpy(pSGList, io->cSGList, 876 (ULONG) io->BlocksXferred * (ULONG) io->BlockSize, 877 aws->buf, io->BlockSize, BUF_TO_SG); 928 CopySgBuf(pSGList, io->cSGList, (ULONG)io->BlocksXferred * (ULONG)io->BlockSize, 929 aws->buf, io->BlockSize, BUF_TO_SGL); 878 930 } 879 931 … … 902 954 int p = iorb_unit_port(pIorb); 903 955 int d = iorb_unit_device(pIorb); 956 ULONGLONG ullLba = io->RBA; 904 957 int rc; 905 958 … … 910 963 } 911 964 965 if (add_workspace(pIorb)->fIs64bit) 966 { 967 ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA; 968 } 969 912 970 /* prepare verify command */ 913 if ( io->RBA>= (1UL << 28) || io->BlockCount > 256)971 if (ullLba >= (1UL << 28) || io->BlockCount > 256) 914 972 { 915 973 /* need LBA48 for this command */ … … 919 977 } 920 978 rc = ata_cmd(ai, p, d, slot, ATA_CMD_VERIFY_EXT, 921 AP_SECTOR_48, io->RBA, 0,979 AP_SECTOR_48, ullLba, 922 980 AP_COUNT, io->BlockCount, 923 981 AP_DEVICE, 0x40, … … 925 983 } else { 926 984 rc = ata_cmd(ai, p, d, slot, ATA_CMD_VERIFY, 927 AP_SECTOR_28, io->RBA,985 AP_SECTOR_28, (ULONG)ullLba, 928 986 AP_COUNT, io->BlockCount & 0xffU, 929 987 AP_DEVICE, 0x40, … … 935 993 936 994 /****************************************************************************** 995 * Fabricate ATA WRITE command based on the capabilities of the corresponding 996 * device and the paramters set from above (NCQ, etc) 997 */ 998 static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot, 999 ULONGLONG ullLba, ULONG count, SCATGATENTRY *sg_list, 1000 ULONG sg_cnt, int write_through) 1001 { 1002 int rc; 1003 1004 if (ullLba >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq) 1005 { 1006 /* need LBA48 for this command */ 1007 if (!ai->ports[p].devs[d].lba48) 1008 { 1009 iorb_seterr(pIorb, IOERR_RBA_LIMIT); 1010 return(-1); 1011 } 1012 if (add_workspace(pIorb)->is_ncq) 1013 { 1014 /* use NCQ write; count goes into feature register, tag into count! */ 1015 rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE, 1016 AP_SECTOR_48, ullLba, 1017 AP_FEATURES, count, 1018 /* tag = slot */ 1019 AP_COUNT, (slot << 3), 1020 AP_SGLIST, sg_list, sg_cnt, 1021 AP_DEVICE, 0x40, 1022 /* force unit access */ 1023 AP_DEVICE, (write_through && !force_write_cache) ? 0x80 : 0, 1024 AP_WRITE, 1, 1025 AP_END); 1026 } 1027 else 1028 { 1029 rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT, 1030 AP_SECTOR_48, ullLba, 1031 AP_COUNT, count, 1032 AP_SGLIST, sg_list, sg_cnt, 1033 AP_DEVICE, 0x40, 1034 AP_WRITE, 1, 1035 AP_END); 1036 } 1037 } 1038 else 1039 { 1040 rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE, 1041 AP_SECTOR_28, (ULONG)ullLba, 1042 AP_COUNT, count & 0xffU, 1043 AP_SGLIST, sg_list, sg_cnt, 1044 AP_DEVICE, 0x40, 1045 AP_WRITE, 1, 1046 AP_END); 1047 } 1048 1049 return(rc); 1050 } 1051 1052 /****************************************************************************** 937 1053 * Write sectors to AHCI device. 938 1054 */ … … 942 1058 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList); 943 1059 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb); 944 ULONG sector= io->RBA + io->BlocksXferred;1060 ULONGLONG ullLba = io->RBA + io->BlocksXferred; 945 1061 USHORT count = io->BlockCount - io->BlocksXferred; 946 1062 USHORT sg_indx; … … 962 1078 } 963 1079 1080 if (add_workspace(pIorb)->fIs64bit) 1081 { 1082 ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred; 1083 } 1084 964 1085 /* prepare write command while keeping an eye on S/G count limitations */ 965 1086 do { 966 sg_indx = ata_get_sg_indx(io);1087 sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize); 967 1088 sg_cnt = io->cSGList - sg_indx; 968 if ((rc = ata_cmd_write(pIorb, ai, p, d, slot, sector, count,1089 if ((rc = ata_cmd_write(pIorb, ai, p, d, slot, ullLba, count, 969 1090 pSGList + sg_indx, sg_cnt, 970 1091 io->Flags & XIO_DISABLE_HW_WRITE_CACHE)) > 0) 971 1092 { 972 1093 /* couldn't map all S/G elements */ 973 ata_max_sg_cnt(io, sg_indx, (USHORT) 1094 ata_max_sg_cnt(io, sg_indx, (USHORT)rc, &sg_cnt, &count); 974 1095 } 975 1096 } while (rc > 0 && sg_cnt > 0); … … 1010 1131 ADD_WORKSPACE *aws = add_workspace(pIorb); 1011 1132 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb); 1012 ULONG sector= io->RBA + io->BlocksXferred;1133 ULONGLONG ullLba = io->RBA + io->BlocksXferred; 1013 1134 SCATGATENTRY sg_single; 1014 1135 int p = iorb_unit_port(pIorb); … … 1016 1137 int rc; 1017 1138 1018 DPRINTF(7,"ata_write_unaligned(%d.%d.%d, %d)\n", ad_no(ai), p, d, sector); 1139 if (add_workspace(pIorb)->fIs64bit) 1140 { 1141 ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred; 1142 } 1143 1144 DPRINTF(7,"ata_write_unaligned(%d.%d.%d, %lld)\n", ad_no(ai), p, d, ullLba); 1019 1145 1020 1146 /* allocate transfer buffer */ … … 1026 1152 1027 1153 /* copy next sector from S/G list to transfer buffer */ 1028 sg_memcpy(pSGList, io->cSGList, 1029 (ULONG) io->BlocksXferred * (ULONG) io->BlockSize, 1030 aws->buf, io->BlockSize, SG_TO_BUF); 1154 CopySgBuf(pSGList, io->cSGList, (ULONG)io->BlocksXferred * (ULONG)io->BlockSize, 1155 aws->buf, io->BlockSize, SGL_TO_BUF); 1031 1156 1032 1157 /* prepare write command using transfer buffer */ 1033 1158 sg_single.ppXferBuf = MemPhysAdr(aws->buf); 1034 1159 sg_single.XferBufLen = io->BlockSize; 1035 rc = ata_cmd_write(pIorb, ai, p, d, slot, sector, 1, &sg_single, 1,1160 rc = ata_cmd_write(pIorb, ai, p, d, slot, ullLba, 1, &sg_single, 1, 1036 1161 io->Flags & XIO_DISABLE_HW_WRITE_CACHE); 1037 1162 … … 1250 1375 1251 1376 /****************************************************************************** 1252 * Fabricate ATA READ command based on the capabilities of the corresponding1253 * device and the paramters set from above (NCQ, etc).1254 */1255 static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,1256 ULONG sector, ULONG count, SCATGATENTRY *sg_list,1257 ULONG sg_cnt)1258 {1259 int rc;1260 1261 if (sector >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)1262 {1263 /* need LBA48 for this command */1264 if (!ai->ports[p].devs[d].lba48)1265 {1266 iorb_seterr(pIorb, IOERR_RBA_LIMIT);1267 return(-1);1268 }1269 if (add_workspace(pIorb)->is_ncq)1270 {1271 /* use NCQ read; count goes into feature register, tag into count! */1272 rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ,1273 AP_SECTOR_48, sector, 0,1274 AP_FEATURES, count,1275 AP_COUNT, (slot << 3), /* tag == slot */1276 AP_SGLIST, sg_list, sg_cnt,1277 AP_DEVICE, 0x40,1278 AP_END);1279 }1280 else1281 {1282 rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT,1283 AP_SECTOR_48, sector, 0,1284 AP_COUNT, count,1285 AP_SGLIST, sg_list, sg_cnt,1286 AP_DEVICE, 0x40,1287 AP_END);1288 }1289 1290 }1291 else1292 {1293 rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ,1294 AP_SECTOR_28, sector,1295 AP_COUNT, count & 0xffU,1296 AP_SGLIST, sg_list, sg_cnt,1297 AP_DEVICE, 0x40,1298 AP_END);1299 }1300 1301 return(rc);1302 }1303 1304 /******************************************************************************1305 * Fabricate ATA WRITE command based on the capabilities of the corresponding1306 * device and the paramters set from above (NCQ, etc)1307 */1308 static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,1309 ULONG sector, ULONG count, SCATGATENTRY *sg_list,1310 ULONG sg_cnt, int write_through)1311 {1312 int rc;1313 1314 if (sector >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)1315 {1316 /* need LBA48 for this command */1317 if (!ai->ports[p].devs[d].lba48)1318 {1319 iorb_seterr(pIorb, IOERR_RBA_LIMIT);1320 return(-1);1321 }1322 if (add_workspace(pIorb)->is_ncq)1323 {1324 /* use NCQ write; count goes into feature register, tag into count! */1325 rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE,1326 AP_SECTOR_48, sector, 0,1327 AP_FEATURES, count,1328 /* tag = slot */1329 AP_COUNT, (slot << 3),1330 AP_SGLIST, sg_list, sg_cnt,1331 AP_DEVICE, 0x40,1332 /* force unit access */1333 AP_DEVICE, (write_through && !force_write_cache) ? 0x80 : 0,1334 AP_WRITE, 1,1335 AP_END);1336 }1337 else1338 {1339 rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT,1340 AP_SECTOR_48, sector, 0,1341 AP_COUNT, count,1342 AP_SGLIST, sg_list, sg_cnt,1343 AP_DEVICE, 0x40,1344 AP_WRITE, 1,1345 AP_END);1346 }1347 }1348 else1349 {1350 rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE,1351 AP_SECTOR_28, sector,1352 AP_COUNT, count & 0xffU,1353 AP_SGLIST, sg_list, sg_cnt,1354 AP_DEVICE, 0x40,1355 AP_WRITE, 1,1356 AP_END);1357 }1358 1359 return(rc);1360 }1361 1362 /******************************************************************************1363 * Copy block from S/G list to virtual address or vice versa.1364 */1365 void sg_memcpy(SCATGATENTRY *sg_list, USHORT sg_cnt, ULONG sg_off,1366 void *buf, USHORT len, SG_MEMCPY_DIRECTION dir)1367 {1368 USHORT i;1369 USHORT l;1370 ULONG phys_addr;1371 ULONG pos = 0;1372 char *p;1373 1374 /* walk through S/G list to find the elements involved in the operation */1375 for (i = 0; i < sg_cnt && len > 0; i++)1376 {1377 if (pos <= sg_off && pos + sg_list[i].XferBufLen > sg_off)1378 {1379 /* this S/G element intersects with the block to be copied */1380 phys_addr = sg_list[i].ppXferBuf + (sg_off - pos);1381 if ((l = sg_list[i].XferBufLen - (sg_off - pos)) > len)1382 {1383 l = len;1384 }1385 1386 if (Dev32Help_PhysToLin(phys_addr, l, (PVOID) &p))1387 {1388 panic(__func__": DevHelp_PhysToLin() failed");1389 }1390 if (dir == SG_TO_BUF)1391 {1392 memcpy(buf, p, l);1393 }1394 else1395 {1396 memcpy(p, buf, l);1397 }1398 sg_off += l;1399 buf = (char *) buf + l;1400 len -= l;1401 }1402 1403 pos += sg_list[i].XferBufLen;1404 }1405 }1406 1407 /******************************************************************************1408 1377 * Halt processing by submitting an internal error. This is a last resort and 1409 1378 * should only be called when the system state is corrupt.
Note:
See TracChangeset
for help on using the changeset viewer.