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