415fdececf62a35119f899feda94020bab9821ec
[people/xl0/gpxe.git] / src / core / disk.c
1 #include <etherboot.h>
2 #include <disk.h>
3
4 #warning "disk.c is currently broken"
5 #if 0
6
7 #undef disk_disable
8
9 static int dummy(void *unused __unused)
10 {
11         return (0);
12 }
13
14 static unsigned char disk_buffer[DISK_BUFFER_SIZE];
15 struct disk disk =
16 {
17         {
18                 0,                              /* dev.disable */
19                 {
20                         0,
21                         0,
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 */
31         },
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 */
41         
42         0,              /* disk_offset */
43         0,              /* direction */
44 };
45
46
47 static int disk_read(
48         struct disk *disk, unsigned char *buffer, sector_t sector)
49 {
50         int result;
51         sector_t base_sector;
52
53         /* Note: I do not handle disk wrap around here! */
54
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;
63         }
64
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;
72         }
73         /* Service the request from the track cache */
74         memcpy(buffer, disk->buffer + ((sector - base_sector)<<9), SECTOR_SIZE);
75         return 0;
76 }
77         
78 static int disk_read_sectors(
79         struct disk *disk,
80         unsigned char *buffer,
81         sector_t base_sector, unsigned int sectors)
82 {
83         sector_t sector = 0;
84         unsigned long offset;
85         int result = 0;
86
87         for(offset = 0; offset < sectors; offset++) {
88                 sector = base_sector + offset;
89                 if (sector >= disk->sectors) {
90                         sector -= disk->sectors;
91                 }
92                 result = disk_read(disk, buffer + (offset << 9), sector);
93                 if (result < 0)
94                         break;
95         }
96         if (result < 0) {
97                 printf("disk read error at 0x%lx\n", sector);
98         }
99         return result;
100 }
101
102 static os_download_t probe_buffer(unsigned char *buffer, unsigned int len,
103         int increment, unsigned int offset, unsigned int *roffset)
104 {
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;
111         }
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;
118 }
119
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)
125 {
126         sector_t skip_sectors;
127
128         skip_sectors = 0;
129         while(1) {
130                 skip_sectors = os_download(buffer + offset, 
131                         (buf_sectors << 9) - offset, 0);
132
133                 block += skip_sectors + buf_sectors;
134                 if (block >= disk->sectors) {
135                         block -= disk->sectors;
136                 }
137
138                 offset = 0;
139                 buf_sectors = 1;
140                 if (disk_read_sectors(disk, buffer, block, 1) < 0) {
141                         return 0;
142                 }
143         }
144         return -1;
145 }
146
147 int disk_probe(struct dev *dev)
148 {
149         struct disk *disk = (struct disk *)dev;
150         if (dev->how_probe == PROBE_NEXT) {
151                 disk->drive += 1;
152         }
153         return probe(dev);
154 }
155
156
157 int disk_load_configuration(struct dev *dev)
158 {
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;
164 }
165
166 int disk_load(struct dev *dev)
167 {
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;
180
181
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.
188          */
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;
195         }
196         /* let probe buffer assume offset always needs to be incremented */
197         offset = (len/2 + ((disk->disk_offset) & 0x1ff)) - inc;
198
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.
201          */
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);
207         }
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;
212         }
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;
218         }
219         os_download = probe_buffer(buffer, len, inc, offset, &offset);
220         if (!os_download) {
221                 result = -1;
222                 goto out;
223         }
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;
230 }
231
232 int url_file(const char *name,
233         int (*fnc)(unsigned char *, unsigned int, unsigned int, int) __unused)
234 {
235         unsigned int drive;
236         unsigned long  disk_offset;
237         int direction;
238         int type;
239
240         disk_offset = 0;
241         direction = 1;
242         if (memcmp(name, "disk", 4) == 0) {
243                 type = DISK_DRIVER;
244                 name += 4;
245         }
246         else if (memcmp(name, "floppy", 6) == 0) {
247                 type = FLOPPY_DRIVER;
248                 name += 6;
249         }
250         else {
251                 printf("Unknown device type\n");
252                 return 0;
253         }
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);
259         }
260         if (name[0]) {
261                 printf("Junk '%s' at end of disk url\n", name);
262                 return 0;
263         }
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;
275                 }
276         } while(disk.drive < drive);
277         disk.direction = direction;
278         disk.disk_offset = disk_offset;
279         
280         return disk_load(&disk.dev);
281 }
282
283 void disk_disable(void)
284 {
285         disable(&disk.dev);
286 }
287
288
289 #endif