Merge branch 'scsi2sd-util'
[SCSI2SD.git] / software / SCSI2SD / src / geometry.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "geometry.h"\r
19 #include "scsi.h"\r
20 \r
21 #include <string.h>\r
22 \r
23 uint32_t getScsiCapacity(\r
24         uint32_t sdSectorStart,\r
25         uint16_t bytesPerSector,\r
26         uint32_t scsiSectors)\r
27 {\r
28         uint32_t capacity =\r
29                 (sdDev.capacity - sdSectorStart) /\r
30                         SDSectorsPerSCSISector(bytesPerSector);\r
31         if (scsiSectors && (capacity > scsiSectors))\r
32         {\r
33                 capacity = scsiSectors;\r
34         }\r
35         return capacity;\r
36 }\r
37 \r
38 \r
39 uint32_t SCSISector2SD(\r
40         uint32_t sdSectorStart,\r
41         uint16_t bytesPerSector,\r
42         uint32_t scsiSector)\r
43 {\r
44         return scsiSector * SDSectorsPerSCSISector(bytesPerSector) + sdSectorStart;\r
45 }\r
46 \r
47 // Standard mapping according to ECMA-107 and ISO/IEC 9293:1994\r
48 // Sector always starts at 1. There is no 0 sector.\r
49 uint64 CHS2LBA(uint32 c, uint8 h, uint32 s)\r
50 {\r
51         return (\r
52                 (((uint64)c) * SCSI_HEADS_PER_CYLINDER + h) *\r
53                         (uint64) SCSI_SECTORS_PER_TRACK\r
54                 ) + (s - 1);\r
55 }\r
56 \r
57 \r
58 void LBA2CHS(uint32 lba, uint32* c, uint8* h, uint32* s)\r
59 {\r
60         *c = lba / (SCSI_SECTORS_PER_TRACK * SCSI_HEADS_PER_CYLINDER);\r
61         *h = (lba / SCSI_SECTORS_PER_TRACK) % SCSI_HEADS_PER_CYLINDER;\r
62         *s = (lba % SCSI_SECTORS_PER_TRACK) + 1;\r
63 }\r
64 \r
65 uint64 scsiByteAddress(\r
66         uint16_t bytesPerSector,\r
67         int format,\r
68         const uint8* addr)\r
69 {\r
70         uint64 result;\r
71         switch (format)\r
72         {\r
73         case ADDRESS_BLOCK:\r
74         {\r
75                 uint32 lba =\r
76                         (((uint32) addr[0]) << 24) +\r
77                         (((uint32) addr[1]) << 16) +\r
78                         (((uint32) addr[2]) << 8) +\r
79                         addr[3];\r
80 \r
81                 result = (uint64_t) bytesPerSector * lba;\r
82         } break;\r
83 \r
84         case ADDRESS_PHYSICAL_BYTE:\r
85         {\r
86                 uint32 cyl =\r
87                         (((uint32) addr[0]) << 16) +\r
88                         (((uint32) addr[1]) << 8) +\r
89                         addr[2];\r
90 \r
91                 uint8 head = addr[3];\r
92 \r
93                 uint32 bytes =\r
94                         (((uint32) addr[4]) << 24) +\r
95                         (((uint32) addr[5]) << 16) +\r
96                         (((uint32) addr[6]) << 8) +\r
97                         addr[7];\r
98 \r
99                 result = CHS2LBA(cyl, head, 1) * (uint64_t) bytesPerSector + bytes;\r
100         } break;\r
101 \r
102         case ADDRESS_PHYSICAL_SECTOR:\r
103         {\r
104                 uint32 cyl =\r
105                         (((uint32) addr[0]) << 16) +\r
106                         (((uint32) addr[1]) << 8) +\r
107                         addr[2];\r
108 \r
109                 uint8 head = scsiDev.data[3];\r
110 \r
111                 uint32 sector =\r
112                         (((uint32) addr[4]) << 24) +\r
113                         (((uint32) addr[5]) << 16) +\r
114                         (((uint32) addr[6]) << 8) +\r
115                         addr[7];\r
116 \r
117                 result = CHS2LBA(cyl, head, sector) * (uint64_t) bytesPerSector;\r
118         } break;\r
119 \r
120         default:\r
121                 result = (uint64) -1;\r
122         }\r
123 \r
124         return result;\r
125 }\r
126 \r
127 \r
128 void scsiSaveByteAddress(\r
129         uint16_t bytesPerSector,\r
130         int format,\r
131         uint64 byteAddr,\r
132         uint8* buf)\r
133 {\r
134         uint32 lba = byteAddr / bytesPerSector;\r
135         uint32 byteOffset = byteAddr % bytesPerSector;\r
136 \r
137         switch (format)\r
138         {\r
139         case ADDRESS_BLOCK:\r
140         {\r
141                 buf[0] = lba >> 24;\r
142                 buf[1] = lba >> 16;\r
143                 buf[2] = lba >> 8;\r
144                 buf[3] = lba;\r
145 \r
146                 buf[4] = 0;\r
147                 buf[5] = 0;\r
148                 buf[6] = 0;\r
149                 buf[7] = 0;\r
150         } break;\r
151 \r
152         case ADDRESS_PHYSICAL_BYTE:\r
153         {\r
154                 uint32 cyl;\r
155                 uint8 head;\r
156                 uint32 sector;\r
157                 uint32 bytes;\r
158 \r
159                 LBA2CHS(lba, &cyl, &head, &sector);\r
160 \r
161                 bytes = sector * bytesPerSector + byteOffset;\r
162 \r
163                 buf[0] = cyl >> 16;\r
164                 buf[1] = cyl >> 8;\r
165                 buf[2] = cyl;\r
166 \r
167                 buf[3] = head;\r
168 \r
169                 buf[4] = bytes >> 24;\r
170                 buf[5] = bytes >> 16;\r
171                 buf[6] = bytes >> 8;\r
172                 buf[7] = bytes;\r
173         } break;\r
174 \r
175         case ADDRESS_PHYSICAL_SECTOR:\r
176         {\r
177                 uint32 cyl;\r
178                 uint8 head;\r
179                 uint32 sector;\r
180 \r
181                 LBA2CHS(lba, &cyl, &head, &sector);\r
182 \r
183                 buf[0] = cyl >> 16;\r
184                 buf[1] = cyl >> 8;\r
185                 buf[2] = cyl;\r
186 \r
187                 buf[3] = head;\r
188 \r
189                 buf[4] = sector >> 24;\r
190                 buf[5] = sector >> 16;\r
191                 buf[6] = sector >> 8;\r
192                 buf[7] = sector;\r
193         } break;\r
194 \r
195         default:\r
196                 memset(buf, 0, 8);\r
197         }\r
198 \r
199 }\r
200 \r