1
2
3
4
5
6
7
8
9
10
11
12
13#define __NO_VERSION__
14#include <linux/module.h>
15
16#include <linux/fs.h>
17#include <linux/genhd.h>
18#include <linux/kernel.h>
19#include <linux/blk.h>
20#include <asm/unaligned.h>
21#include "scsi.h"
22#include "hosts.h"
23#include "sd.h"
24#include <scsi/scsicam.h>
25
26static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
27 unsigned int *secs);
28
29
30
31
32
33
34
35
36
37
38
39
40
41int scsicam_bios_param(Disk * disk,
42 kdev_t dev,
43 int *ip )
44{
45 struct buffer_head *bh;
46 int ret_code;
47 int size = disk->capacity;
48 unsigned long temp_cyl;
49
50 if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
51 return -1;
52
53
54 ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2,
55 (unsigned int *) ip + 0, (unsigned int *) ip + 1);
56 brelse(bh);
57
58 if (ret_code == -1) {
59
60
61
62 ret_code = setsize((unsigned long) size, (unsigned int *) ip + 2,
63 (unsigned int *) ip + 0, (unsigned int *) ip + 1);
64 }
65
66
67 if (ret_code || ip[0] > 255 || ip[1] > 63) {
68 ip[0] = 64;
69 ip[1] = 32;
70 temp_cyl = size / (ip[0] * ip[1]);
71 if (temp_cyl > 65534) {
72 ip[0] = 255;
73 ip[1] = 63;
74 }
75 ip[2] = size / (ip[0] * ip[1]);
76 }
77 return 0;
78}
79
80
81
82
83
84
85
86
87
88
89
90
91int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
92 unsigned int *cyls, unsigned int *hds, unsigned int *secs)
93{
94 struct partition *p, *largest = NULL;
95 int i, largest_cyl;
96 int cyl, ext_cyl, end_head, end_cyl, end_sector;
97 unsigned int logical_end, physical_end, ext_physical_end;
98
99
100 if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
101 for (largest_cyl = -1, p = (struct partition *)
102 (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
103 if (!p->sys_ind)
104 continue;
105#ifdef DEBUG
106 printk("scsicam_bios_param : partition %d has system \n",
107 i);
108#endif
109 cyl = p->cyl + ((p->sector & 0xc0) << 2);
110 if (cyl > largest_cyl) {
111 largest_cyl = cyl;
112 largest = p;
113 }
114 }
115 }
116 if (largest) {
117 end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
118 end_head = largest->end_head;
119 end_sector = largest->end_sector & 0x3f;
120
121 if (end_head + 1 == 0 || end_sector == 0)
122 return -1;
123
124#ifdef DEBUG
125 printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
126 end_head, end_cyl, end_sector);
127#endif
128
129 physical_end = end_cyl * (end_head + 1) * end_sector +
130 end_head * end_sector + end_sector;
131
132
133 logical_end = get_unaligned(&largest->start_sect)
134 + get_unaligned(&largest->nr_sects);
135
136
137 ext_cyl = (logical_end - (end_head * end_sector + end_sector))
138 / (end_head + 1) / end_sector;
139 ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
140 end_head * end_sector + end_sector;
141
142#ifdef DEBUG
143 printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
144 ,logical_end, physical_end, ext_physical_end, ext_cyl);
145#endif
146
147 if ((logical_end == physical_end) ||
148 (end_cyl == 1023 && ext_physical_end == logical_end)) {
149 *secs = end_sector;
150 *hds = end_head + 1;
151 *cyls = capacity / ((end_head + 1) * end_sector);
152 return 0;
153 }
154#ifdef DEBUG
155 printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
156 logical_end, physical_end);
157#endif
158 }
159 return -1;
160}
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
197 unsigned int *secs)
198{
199 unsigned int rv = 0;
200 unsigned long heads, sectors, cylinders, temp;
201
202 cylinders = 1024L;
203 sectors = 62L;
204
205 temp = cylinders * sectors;
206 heads = capacity / temp;
207 if (capacity % temp) {
208 heads++;
209 temp = cylinders * heads;
210 sectors = capacity / temp;
211
212 if (capacity % temp) {
213 sectors++;
214 temp = heads * sectors;
215 cylinders = capacity / temp;
216 }
217 }
218 if (cylinders == 0)
219 rv = (unsigned) -1;
220
221 *cyls = (unsigned int) cylinders;
222 *secs = (unsigned int) sectors;
223 *hds = (unsigned int) heads;
224 return (rv);
225}
226