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