Added configurable block-size support
[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 {\r
25         uint32_t capacity = sdDev.capacity / SDSectorsPerSCSISector();\r
26         if (config->maxSectors && (capacity > config->maxSectors))\r
27         {\r
28                 capacity = config->maxSectors;\r
29         }\r
30         return capacity;\r
31 }\r
32 \r
33 \r
34 uint32_t SCSISector2SD(uint32_t scsiSector)\r
35 {\r
36         return scsiSector * SDSectorsPerSCSISector();\r
37 }\r
38 \r
39 // Standard mapping according to ECMA-107 and ISO/IEC 9293:1994\r
40 // Sector always starts at 1. There is no 0 sector.\r
41 uint64 CHS2LBA(uint32 c, uint8 h, uint32 s)\r
42 {\r
43         return (\r
44                 (((uint64)c) * SCSI_HEADS_PER_CYLINDER + h) *\r
45                         (uint64) SCSI_SECTORS_PER_TRACK\r
46                 ) + (s - 1);\r
47 }\r
48 \r
49 \r
50 void LBA2CHS(uint32 lba, uint32* c, uint8* h, uint32* s)\r
51 {\r
52         *c = lba / (SCSI_SECTORS_PER_TRACK * SCSI_HEADS_PER_CYLINDER);\r
53         *h = (lba / SCSI_SECTORS_PER_TRACK) % SCSI_HEADS_PER_CYLINDER;\r
54         *s = (lba % SCSI_SECTORS_PER_TRACK) + 1;\r
55 }\r
56 \r
57 uint64 scsiByteAddress(int format, const uint8* addr)\r
58 {\r
59         uint64 result;\r
60         switch (format)\r
61         {\r
62         case ADDRESS_BLOCK:\r
63         {\r
64                 uint32 lba =\r
65                         (((uint32) addr[0]) << 24) +\r
66                         (((uint32) addr[1]) << 16) +\r
67                         (((uint32) addr[2]) << 8) +\r
68                         addr[3];\r
69 \r
70                 result = (uint64_t) config->bytesPerSector * lba;\r
71         } break;\r
72 \r
73         case ADDRESS_PHYSICAL_BYTE:\r
74         {\r
75                 uint32 cyl =\r
76                         (((uint32) addr[0]) << 16) +\r
77                         (((uint32) addr[1]) << 8) +\r
78                         addr[2];\r
79 \r
80                 uint8 head = addr[3];\r
81 \r
82                 uint32 bytes =\r
83                         (((uint32) addr[4]) << 24) +\r
84                         (((uint32) addr[5]) << 16) +\r
85                         (((uint32) addr[6]) << 8) +\r
86                         addr[7];\r
87 \r
88                 result = CHS2LBA(cyl, head, 1) * (uint64_t) config->bytesPerSector + bytes;\r
89         } break;\r
90 \r
91         case ADDRESS_PHYSICAL_SECTOR:\r
92         {\r
93                 uint32 cyl =\r
94                         (((uint32) addr[0]) << 16) +\r
95                         (((uint32) addr[1]) << 8) +\r
96                         addr[2];\r
97 \r
98                 uint8 head = scsiDev.data[3];\r
99 \r
100                 uint32 sector =\r
101                         (((uint32) addr[4]) << 24) +\r
102                         (((uint32) addr[5]) << 16) +\r
103                         (((uint32) addr[6]) << 8) +\r
104                         addr[7];\r
105 \r
106                 result = CHS2LBA(cyl, head, sector) * (uint64_t) config->bytesPerSector;\r
107         } break;\r
108 \r
109         default:\r
110                 result = (uint64) -1;\r
111         }\r
112 \r
113         return result;\r
114 }\r
115 \r
116 \r
117 void scsiSaveByteAddress(int format, uint64 byteAddr, uint8* buf)\r
118 {\r
119         uint32 lba = byteAddr / config->bytesPerSector;\r
120         uint32 byteOffset = byteAddr % config->bytesPerSector;\r
121 \r
122         switch (format)\r
123         {\r
124         case ADDRESS_BLOCK:\r
125         {\r
126                 buf[0] = lba >> 24;\r
127                 buf[1] = lba >> 16;\r
128                 buf[2] = lba >> 8;\r
129                 buf[3] = lba;\r
130 \r
131                 buf[4] = 0;\r
132                 buf[5] = 0;\r
133                 buf[6] = 0;\r
134                 buf[7] = 0;\r
135         } break;\r
136 \r
137         case ADDRESS_PHYSICAL_BYTE:\r
138         {\r
139                 uint32 cyl;\r
140                 uint8 head;\r
141                 uint32 sector;\r
142                 uint32 bytes;\r
143 \r
144                 LBA2CHS(lba, &cyl, &head, &sector);\r
145 \r
146                 bytes = sector * config->bytesPerSector + byteOffset;\r
147 \r
148                 buf[0] = cyl >> 16;\r
149                 buf[1] = cyl >> 8;\r
150                 buf[2] = cyl;\r
151 \r
152                 buf[3] = head;\r
153 \r
154                 buf[4] = bytes >> 24;\r
155                 buf[5] = bytes >> 16;\r
156                 buf[6] = bytes >> 8;\r
157                 buf[7] = bytes;\r
158         } break;\r
159 \r
160         case ADDRESS_PHYSICAL_SECTOR:\r
161         {\r
162                 uint32 cyl;\r
163                 uint8 head;\r
164                 uint32 sector;\r
165 \r
166                 LBA2CHS(lba, &cyl, &head, &sector);\r
167 \r
168                 buf[0] = cyl >> 16;\r
169                 buf[1] = cyl >> 8;\r
170                 buf[2] = cyl;\r
171 \r
172                 buf[3] = head;\r
173 \r
174                 buf[4] = sector >> 24;\r
175                 buf[5] = sector >> 16;\r
176                 buf[6] = sector >> 8;\r
177                 buf[7] = sector;\r
178         } break;\r
179 \r
180         default:\r
181                 memset(buf, 0, 8);\r
182         }\r
183 \r
184 }\r
185 \r