0666b5a2863bd185a39580e67a6c61b74b975fd9
[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_t CHS2LBA(\r
50         uint32_t c,\r
51         uint8_t h,\r
52         uint32_t s,\r
53         uint16_t headsPerCylinder,\r
54         uint16_t sectorsPerTrack)\r
55 {\r
56         return (\r
57                 (((uint64_t)c) * headsPerCylinder + h) *\r
58                         (uint64_t) sectorsPerTrack\r
59                 ) + (s - 1);\r
60 }\r
61 \r
62 \r
63 void LBA2CHS(\r
64         uint32_t lba,\r
65         uint32_t* c,\r
66         uint8_t* h,\r
67         uint32_t* s,\r
68         uint16_t headsPerCylinder,\r
69         uint16_t sectorsPerTrack)\r
70 {\r
71         *c = lba / (((uint32_t) sectorsPerTrack) * headsPerCylinder);\r
72         *h = (lba / sectorsPerTrack) % headsPerCylinder;\r
73         *s = (lba % sectorsPerTrack) + 1;\r
74 }\r
75 \r
76 uint64_t scsiByteAddress(\r
77         uint16_t bytesPerSector,\r
78         uint16_t headsPerCylinder,\r
79         uint16_t sectorsPerTrack,\r
80         int format,\r
81         const uint8_t* addr)\r
82 {\r
83         uint64_t result;\r
84         switch (format)\r
85         {\r
86         case ADDRESS_BLOCK:\r
87         {\r
88                 uint32_t lba =\r
89                         (((uint32_t) addr[0]) << 24) +\r
90                         (((uint32_t) addr[1]) << 16) +\r
91                         (((uint32_t) addr[2]) << 8) +\r
92                         addr[3];\r
93 \r
94                 result = (uint64_t) bytesPerSector * lba;\r
95         } break;\r
96 \r
97         case ADDRESS_PHYSICAL_BYTE:\r
98         {\r
99                 uint32_t cyl =\r
100                         (((uint32_t) addr[0]) << 16) +\r
101                         (((uint32_t) addr[1]) << 8) +\r
102                         addr[2];\r
103 \r
104                 uint8_t head = addr[3];\r
105 \r
106                 uint32_t bytes =\r
107                         (((uint32_t) addr[4]) << 24) +\r
108                         (((uint32_t) addr[5]) << 16) +\r
109                         (((uint32_t) addr[6]) << 8) +\r
110                         addr[7];\r
111 \r
112                 result = CHS2LBA(cyl, head, 1, headsPerCylinder, sectorsPerTrack) *\r
113                         (uint64_t) bytesPerSector + bytes;\r
114         } break;\r
115 \r
116         case ADDRESS_PHYSICAL_SECTOR:\r
117         {\r
118                 uint32 cyl =\r
119                         (((uint32_t) addr[0]) << 16) +\r
120                         (((uint32_t) addr[1]) << 8) +\r
121                         addr[2];\r
122 \r
123                 uint8 head = scsiDev.data[3];\r
124 \r
125                 uint32 sector =\r
126                         (((uint32_t) addr[4]) << 24) +\r
127                         (((uint32_t) addr[5]) << 16) +\r
128                         (((uint32_t) addr[6]) << 8) +\r
129                         addr[7];\r
130 \r
131                 result = CHS2LBA(cyl, head, sector, headsPerCylinder, sectorsPerTrack) * (uint64_t) bytesPerSector;\r
132         } break;\r
133 \r
134         default:\r
135                 result = (uint64) -1;\r
136         }\r
137 \r
138         return result;\r
139 }\r
140 \r
141 \r
142 void scsiSaveByteAddress(\r
143         uint16_t bytesPerSector,\r
144         uint16_t headsPerCylinder,\r
145         uint16_t sectorsPerTrack,\r
146         int format,\r
147         uint64_t byteAddr,\r
148         uint8_t* buf)\r
149 {\r
150         uint32_t lba = byteAddr / bytesPerSector;\r
151         uint32_t byteOffset = byteAddr % bytesPerSector;\r
152 \r
153         switch (format)\r
154         {\r
155         case ADDRESS_BLOCK:\r
156         {\r
157                 buf[0] = lba >> 24;\r
158                 buf[1] = lba >> 16;\r
159                 buf[2] = lba >> 8;\r
160                 buf[3] = lba;\r
161 \r
162                 buf[4] = 0;\r
163                 buf[5] = 0;\r
164                 buf[6] = 0;\r
165                 buf[7] = 0;\r
166         } break;\r
167 \r
168         case ADDRESS_PHYSICAL_BYTE:\r
169         {\r
170                 uint32_t cyl;\r
171                 uint8_t head;\r
172                 uint32_t sector;\r
173                 uint32_t bytes;\r
174 \r
175                 LBA2CHS(lba, &cyl, &head, &sector, headsPerCylinder, sectorsPerTrack);\r
176 \r
177                 bytes = sector * bytesPerSector + byteOffset;\r
178 \r
179                 buf[0] = cyl >> 16;\r
180                 buf[1] = cyl >> 8;\r
181                 buf[2] = cyl;\r
182 \r
183                 buf[3] = head;\r
184 \r
185                 buf[4] = bytes >> 24;\r
186                 buf[5] = bytes >> 16;\r
187                 buf[6] = bytes >> 8;\r
188                 buf[7] = bytes;\r
189         } break;\r
190 \r
191         case ADDRESS_PHYSICAL_SECTOR:\r
192         {\r
193                 uint32_t cyl;\r
194                 uint8_t head;\r
195                 uint32_t sector;\r
196 \r
197                 LBA2CHS(lba, &cyl, &head, &sector, headsPerCylinder, sectorsPerTrack);\r
198 \r
199                 buf[0] = cyl >> 16;\r
200                 buf[1] = cyl >> 8;\r
201                 buf[2] = cyl;\r
202 \r
203                 buf[3] = head;\r
204 \r
205                 buf[4] = sector >> 24;\r
206                 buf[5] = sector >> 16;\r
207                 buf[6] = sector >> 8;\r
208                 buf[7] = sector;\r
209         } break;\r
210 \r
211         default:\r
212                 memset(buf, 0, 8);\r
213         }\r
214 \r
215 }\r
216 \r