Updated email mdc's email address
[gpxe.git] / src / core / disk.c
blob2ccd5ff2e127652f2d78e28ae2e8130a29dfbda4
1 #include "etherboot.h"
2 #include "disk.h"
4 #warning "disk.c is currently broken"
5 #if 0
7 #undef disk_disable
9 static int dummy(void *unused __unused)
11 return (0);
14 static unsigned char disk_buffer[DISK_BUFFER_SIZE];
15 struct disk disk =
18 0, /* dev.disable */
22 PCI_BUS_TYPE,
23 }, /* dev.devid */
24 0, /* index */
25 0, /* type */
26 PROBE_FIRST, /* how_probe */
27 PROBE_NONE, /* to_probe */
28 0, /* failsafe */
29 0, /* type_index */
30 {}, /* state */
32 (int (*)(struct disk *, sector_t ))dummy, /* read */
33 0 - 1, /* drive */
34 0, /* hw_sector_size */
35 0, /* sectors_per_read */
36 0, /* bytes */
37 0, /* sectors */
38 0, /* sector */
39 disk_buffer, /* buffer */
40 0, /* priv */
42 0, /* disk_offset */
43 0, /* direction */
47 static int disk_read(
48 struct disk *disk, unsigned char *buffer, sector_t sector)
50 int result;
51 sector_t base_sector;
53 /* Note: I do not handle disk wrap around here! */
55 /* Compute the start of the track cache */
56 base_sector = sector;
57 /* Support sectors_per_read > 1 only on small disks */
58 if ((sizeof(sector_t) > sizeof(unsigned long)) &&
59 (disk->sectors_per_read > 1)) {
60 unsigned long offset;
61 offset = ((unsigned long)sector) % disk->sectors_per_read;
62 base_sector -= offset;
65 /* See if I need to update the track cache */
66 if ((sector < disk->sector) ||
67 sector >= disk->sector + (disk->bytes >> 9)) {
68 twiddle();
69 result = disk->read(disk, base_sector);
70 if (result < 0)
71 return result;
73 /* Service the request from the track cache */
74 memcpy(buffer, disk->buffer + ((sector - base_sector)<<9), SECTOR_SIZE);
75 return 0;
78 static int disk_read_sectors(
79 struct disk *disk,
80 unsigned char *buffer,
81 sector_t base_sector, unsigned int sectors)
83 sector_t sector = 0;
84 unsigned long offset;
85 int result = 0;
87 for(offset = 0; offset < sectors; offset++) {
88 sector = base_sector + offset;
89 if (sector >= disk->sectors) {
90 sector -= disk->sectors;
92 result = disk_read(disk, buffer + (offset << 9), sector);
93 if (result < 0)
94 break;
96 if (result < 0) {
97 printf("disk read error at 0x%lx\n", sector);
99 return result;
102 static os_download_t probe_buffer(unsigned char *buffer, unsigned int len,
103 int increment, unsigned int offset, unsigned int *roffset)
105 os_download_t os_download;
106 unsigned int end;
107 end = 0;
108 os_download = 0;
109 if (increment > 0) {
110 end = len - SECTOR_SIZE;
112 do {
113 offset += increment;
114 os_download = probe_image(buffer + offset, len - offset);
115 } while(!os_download && (offset != end));
116 *roffset = offset;
117 return os_download;
120 static int load_image(
121 struct disk *disk,
122 unsigned char *buffer, unsigned int buf_sectors,
123 sector_t block, unsigned int offset,
124 os_download_t os_download)
126 sector_t skip_sectors;
128 skip_sectors = 0;
129 while(1) {
130 skip_sectors = os_download(buffer + offset,
131 (buf_sectors << 9) - offset, 0);
133 block += skip_sectors + buf_sectors;
134 if (block >= disk->sectors) {
135 block -= disk->sectors;
138 offset = 0;
139 buf_sectors = 1;
140 if (disk_read_sectors(disk, buffer, block, 1) < 0) {
141 return 0;
144 return -1;
147 int disk_probe(struct dev *dev)
149 struct disk *disk = (struct disk *)dev;
150 if (dev->how_probe == PROBE_NEXT) {
151 disk->drive += 1;
153 return probe(dev);
157 int disk_load_configuration(struct dev *dev)
159 /* Start with the very simplest possible disk configuration */
160 struct disk *disk = (struct disk *)dev;
161 disk->direction = (dev->failsafe)?-1:1;
162 disk->disk_offset = 0;
163 return 0;
166 int disk_load(struct dev *dev)
168 struct disk *disk = (struct disk *)dev;
169 /* 16K == 8K in either direction from the start of the disk */
170 static unsigned char buffer[32*SECTOR_SIZE];
171 os_download_t os_download;
172 unsigned int offset;
173 unsigned int len;
174 unsigned int buf_sectors;
175 volatile sector_t block;
176 volatile int inc, increment;
177 int i;
178 int result;
179 jmp_buf real_restart;
182 printf("Searching for image...\n");
183 result = 0;
184 /* Only check for 16byte aligned images */
185 increment = (disk->direction < 0)?-16:16;
186 /* Load a buffer, and see if it contains the start of an image
187 * we can boot from disk.
189 len = sizeof(buffer);
190 buf_sectors = sizeof(buffer) / SECTOR_SIZE;
191 inc = increment;
192 block = (disk->disk_offset) >> 9;
193 if (buf_sectors/2 > block) {
194 block = (disk->sectors - (buf_sectors/2)) + block;
196 /* let probe buffer assume offset always needs to be incremented */
197 offset = (len/2 + ((disk->disk_offset) & 0x1ff)) - inc;
199 /* Catch longjmp so if this image fails to load, I start looking
200 * for the next image where I left off looking for this image.
202 memcpy(&real_restart, &restart_etherboot, sizeof(jmp_buf));
203 i = setjmp(restart_etherboot);
204 if ((i != 0) && (i != -2)) {
205 memcpy(&restart_etherboot, &real_restart, sizeof(jmp_buf));
206 longjmp(restart_etherboot, i);
208 /* Read the canidate sectors into the buffer */
209 if (disk_read_sectors(disk, buffer, block, buf_sectors) < 0) {
210 result = -1;
211 goto out;
213 if (inc == increment) {
214 os_download = probe_buffer(buffer, len, inc, offset, &offset);
215 if (os_download)
216 goto load_image;
217 inc = -inc;
219 os_download = probe_buffer(buffer, len, inc, offset, &offset);
220 if (!os_download) {
221 result = -1;
222 goto out;
224 load_image:
225 printf("Loading image...\n");
226 result = load_image(disk, buffer, buf_sectors, block, offset, os_download);
227 out:
228 memcpy(&restart_etherboot, &real_restart, sizeof(jmp_buf));
229 return result;
232 int url_file(const char *name,
233 int (*fnc)(unsigned char *, unsigned int, unsigned int, int) __unused)
235 unsigned int drive;
236 unsigned long disk_offset;
237 int direction;
238 int type;
240 disk_offset = 0;
241 direction = 1;
242 if (memcmp(name, "disk", 4) == 0) {
243 type = DISK_DRIVER;
244 name += 4;
246 else if (memcmp(name, "floppy", 6) == 0) {
247 type = FLOPPY_DRIVER;
248 name += 6;
250 else {
251 printf("Unknown device type\n");
252 return 0;
254 drive = strtoul(name, &name, 10);
255 if ((name[0] == '+') || (name[0] == '-')) {
256 direction = (name[0] == '-')? -1 : 1;
257 name++;
258 disk_offset = strtoul(name, &name, 10);
260 if (name[0]) {
261 printf("Junk '%s' at end of disk url\n", name);
262 return 0;
264 memset(&disk, 0, sizeof(disk));
265 disk.buffer = disk_buffer;
266 disk.drive = 0;
267 disk.dev.how_probe = PROBE_FIRST;
268 disk.dev.type = type;
269 do {
270 disk_disable();
271 disk.dev.how_probe = disk_probe(&disk.dev);
272 if (disk.dev.how_probe == PROBE_FAILED) {
273 printf("Not that many drives\n");
274 return 0;
276 } while(disk.drive < drive);
277 disk.direction = direction;
278 disk.disk_offset = disk_offset;
280 return disk_load(&disk.dev);
283 void disk_disable(void)
285 disable(&disk.dev);
289 #endif