1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/fs.h>
16#include <linux/genhd.h>
17#include <linux/kernel.h>
18#include <linux/blkdev.h>
19#include <asm/unaligned.h>
20
21#include <scsi/scsicam.h>
22
23
24static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
25 unsigned int *secs);
26
27
28
29
30
31
32
33
34
35unsigned char *scsi_bios_ptable(struct block_device *dev)
36{
37 unsigned char *res = kmalloc(66, GFP_KERNEL);
38 if (res) {
39 struct block_device *bdev = dev->bd_contains;
40 Sector sect;
41 void *data = read_dev_sector(bdev, 0, §);
42 if (data) {
43 memcpy(res, data + 0x1be, 66);
44 put_dev_sector(sect);
45 } else {
46 kfree(res);
47 res = NULL;
48 }
49 }
50 return res;
51}
52EXPORT_SYMBOL(scsi_bios_ptable);
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
68{
69 unsigned char *p;
70 u64 capacity64 = capacity;
71 int ret;
72
73 p = scsi_bios_ptable(bdev);
74 if (!p)
75 return -1;
76
77
78 ret = scsi_partsize(p, (unsigned long)capacity, (unsigned int *)ip + 2,
79 (unsigned int *)ip + 0, (unsigned int *)ip + 1);
80 kfree(p);
81
82 if (ret == -1 && capacity64 < (1ULL << 32)) {
83
84
85
86 ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2,
87 (unsigned int *)ip + 0, (unsigned int *)ip + 1);
88 }
89
90
91
92 if (ret || ip[0] > 255 || ip[1] > 63) {
93 if ((capacity >> 11) > 65534) {
94 ip[0] = 255;
95 ip[1] = 63;
96 } else {
97 ip[0] = 64;
98 ip[1] = 32;
99 }
100
101 if (capacity > 65535*63*255)
102 ip[2] = 65535;
103 else
104 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
105 }
106
107 return 0;
108}
109EXPORT_SYMBOL(scsicam_bios_param);
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125int scsi_partsize(unsigned char *buf, unsigned long capacity,
126 unsigned int *cyls, unsigned int *hds, unsigned int *secs)
127{
128 struct partition *p = (struct partition *)buf, *largest = NULL;
129 int i, largest_cyl;
130 int cyl, ext_cyl, end_head, end_cyl, end_sector;
131 unsigned int logical_end, physical_end, ext_physical_end;
132
133
134 if (*(unsigned short *) (buf + 64) == 0xAA55) {
135 for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) {
136 if (!p->sys_ind)
137 continue;
138#ifdef DEBUG
139 printk("scsicam_bios_param : partition %d has system \n",
140 i);
141#endif
142 cyl = p->cyl + ((p->sector & 0xc0) << 2);
143 if (cyl > largest_cyl) {
144 largest_cyl = cyl;
145 largest = p;
146 }
147 }
148 }
149 if (largest) {
150 end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
151 end_head = largest->end_head;
152 end_sector = largest->end_sector & 0x3f;
153
154 if (end_head + 1 == 0 || end_sector == 0)
155 return -1;
156
157#ifdef DEBUG
158 printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
159 end_head, end_cyl, end_sector);
160#endif
161
162 physical_end = end_cyl * (end_head + 1) * end_sector +
163 end_head * end_sector + end_sector;
164
165
166 logical_end = get_unaligned(&largest->start_sect)
167 + get_unaligned(&largest->nr_sects);
168
169
170 ext_cyl = (logical_end - (end_head * end_sector + end_sector))
171 / (end_head + 1) / end_sector;
172 ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
173 end_head * end_sector + end_sector;
174
175#ifdef DEBUG
176 printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
177 ,logical_end, physical_end, ext_physical_end, ext_cyl);
178#endif
179
180 if ((logical_end == physical_end) ||
181 (end_cyl == 1023 && ext_physical_end == logical_end)) {
182 *secs = end_sector;
183 *hds = end_head + 1;
184 *cyls = capacity / ((end_head + 1) * end_sector);
185 return 0;
186 }
187#ifdef DEBUG
188 printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
189 logical_end, physical_end);
190#endif
191 }
192 return -1;
193}
194EXPORT_SYMBOL(scsi_partsize);
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
231 unsigned int *secs)
232{
233 unsigned int rv = 0;
234 unsigned long heads, sectors, cylinders, temp;
235
236 cylinders = 1024L;
237 sectors = 62L;
238
239 temp = cylinders * sectors;
240 heads = capacity / temp;
241 if (capacity % temp) {
242 heads++;
243 temp = cylinders * heads;
244 sectors = capacity / temp;
245
246 if (capacity % temp) {
247 sectors++;
248 temp = heads * sectors;
249 cylinders = capacity / temp;
250 }
251 }
252 if (cylinders == 0)
253 rv = (unsigned) -1;
254
255 *cyls = (unsigned int) cylinders;
256 *secs = (unsigned int) sectors;
257 *hds = (unsigned int) heads;
258 return (rv);
259}
260