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