]> git.pld-linux.org Git - packages/kernel.git/blob - linux-2.4.20-01-edd.patch
- added description of djurban's branch
[packages/kernel.git] / linux-2.4.20-01-edd.patch
1 diff -urNp linux-651/arch/i386/boot/setup.S linux-660/arch/i386/boot/setup.S
2 --- linux-651/arch/i386/boot/setup.S    
3 +++ linux-660/arch/i386/boot/setup.S    
4 @@ -45,6 +45,10 @@
5   * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
6   * by Robert Schwebel, December 2001 <robert@schwebel.de>
7   *
8 + * BIOS Enhanced Disk Drive support
9 + * by Matt Domsch <Matt_Domsch@dell.com> October 2002
10 + * conformant to T13 Committee www.t13.org
11 + *   projects 1572D, 1484D, 1386D, 1226DT
12   */
13  
14  #include <linux/config.h>
15 @@ -53,6 +57,7 @@
16  #include <linux/compile.h>
17  #include <asm/boot.h>
18  #include <asm/e820.h>
19 +#include <asm/edd.h>    
20  #include <asm/page.h>
21         
22  /* Signature words to ensure LILO loaded us right */
23 @@ -543,6 +548,70 @@ no_32_apm_bios:
24  done_apm_bios:
25  #endif
26  
27 +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
28 +# Do the BIOS Enhanced Disk Drive calls
29 +# This consists of two calls:
30 +#    int 13h ah=41h "Check Extensions Present"
31 +#    int 13h ah=48h "Get Device Parameters"
32 +#
33 +# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
34 +# in the empty_zero_page at EDDBUF.  The first four bytes of which are
35 +# used to store the device number, interface support map and version
36 +# results from fn41.  The following 74 bytes are used to store
37 +# the results from fn48.  Starting from device 80h, fn41, then fn48
38 +# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
39 +# Then the pointer is incremented to store the data for the next call.
40 +# This repeats until either a device doesn't exist, or until EDDMAXNR
41 +# devices have been stored.
42 +# The one tricky part is that ds:si always points four bytes into
43 +# the structure, and the fn41 results are stored at offsets
44 +# from there.  This removes the need to increment the pointer for
45 +# every store, and leaves it ready for the fn48 call.
46 +# A second one-byte buffer, EDDNR, in the empty_zero_page stores
47 +# the number of BIOS devices which exist, up to EDDMAXNR.
48 +# In setup.c, copy_edd() stores both empty_zero_page buffers away
49 +# for later use, as they would get overwritten otherwise. 
50 +# This code is sensitive to the size of the structs in edd.h
51 +edd_start:  
52 +                                               # %ds points to the bootsector
53 +                                                       # result buffer for fn48
54 +       movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
55 +                                               # kept just before that    
56 +       movb    $0, (EDDNR)                     # zero value at EDDNR
57 +       movb    $0x80, %dl                      # BIOS device 0x80
58 +
59 +edd_check_ext:
60 +       movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
61 +       movw    $EDDMAGIC1, %bx                 # magic
62 +       int     $0x13                           # make the call
63 +       jc      edd_done                        # no more BIOS devices
64 +
65 +       cmpw    $EDDMAGIC2, %bx                 # is magic right?
66 +       jne     edd_next                        # nope, next...
67 +
68 +       movb    %dl, %ds:-4(%si)                # store device number
69 +       movb    %ah, %ds:-3(%si)                # store version
70 +       movw    %cx, %ds:-2(%si)                # store extensions
71 +       incb    (EDDNR)                         # note that we stored something
72 +        
73 +edd_get_device_params:  
74 +       movw    $EDDPARMSIZE, %ds:(%si)         # put size
75 +       movb    $GETDEVICEPARAMETERS, %ah       # Function 48
76 +       int     $0x13                           # make the call
77 +                                               # Don't check for fail return
78 +                                               # it doesn't matter.
79 +       movw    %si, %ax                        # increment si
80 +       addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
81 +       movw    %ax, %si
82 +
83 +edd_next:
84 +        incb   %dl                             # increment to next device
85 +               cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
86 +       jb      edd_check_ext                   # keep looping
87 +    
88 +edd_done:   
89 +#endif
90 +
91  # Now we want to move to protected mode ...
92         cmpw    $0, %cs:realmode_swtch
93         jz      rmodeswtch_normal
94 diff -urNp linux-651/arch/i386/config.in linux-660/arch/i386/config.in
95 --- linux-651/arch/i386/config.in       
96 +++ linux-660/arch/i386/config.in       
97 @@ -186,6 +186,10 @@ tristate '/dev/cpu/microcode - Intel IA3
98  tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
99  tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
100  
101 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
102 +   tristate 'BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)' CONFIG_EDD
103 +fi
104 +
105  choice 'High Memory Support' \
106         "off    CONFIG_NOHIGHMEM \
107          4GB    CONFIG_HIGHMEM4G \
108 diff -urNp linux-651/arch/i386/defconfig linux-660/arch/i386/defconfig
109 --- linux-651/arch/i386/defconfig       
110 +++ linux-660/arch/i386/defconfig       
111 @@ -56,6 +56,7 @@ CONFIG_X86_MCE=y
112  # CONFIG_MICROCODE is not set
113  # CONFIG_X86_MSR is not set
114  # CONFIG_X86_CPUID is not set
115 +# CONFIG_EDD is not set
116  CONFIG_NOHIGHMEM=y
117  # CONFIG_HIGHMEM4G is not set
118  # CONFIG_HIGHMEM64G is not set
119 diff -urNp linux-651/arch/i386/kernel/edd.c linux-660/arch/i386/kernel/edd.c
120 --- linux-651/arch/i386/kernel/edd.c    1970-01-01 01:00:00.000000000 +0100
121 +++ linux-660/arch/i386/kernel/edd.c    
122 @@ -0,0 +1,673 @@
123 +/*
124 + * linux/arch/i386/kernel/edd.c
125 + *  Copyright (C) 2002 Dell Computer Corporation
126 + *  by Matt Domsch <Matt_Domsch@dell.com>
127 + *
128 + * BIOS Enhanced Disk Drive Services (EDD)
129 + * conformant to T13 Committee www.t13.org
130 + *   projects 1572D, 1484D, 1386D, 1226DT
131 + *
132 + * This code takes information provided by BIOS EDD calls
133 + * fn41 - Check Extensions Present and
134 + * fn48 - Get Device Parametes with EDD extensions
135 + * made in setup.S, copied to safe structures in setup.c,
136 + * and presents it in driverfs.
137 + *
138 + * This program is free software; you can redistribute it and/or modify
139 + * it under the terms of the GNU General Public License v2.0 as published by
140 + * the Free Software Foundation
141 + *
142 + * This program is distributed in the hope that it will be useful,
143 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
144 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
145 + * GNU General Public License for more details.
146 + *
147 + */
148 +
149 +/*
150 + * TODO:
151 + * - Convert to using /proc instead of driverfs
152 + * - move edd.[ch] to better locations if/when one is decided
153 + * - keep current with 2.5 EDD code changes
154 + */
155 +
156 +#include <linux/module.h>
157 +#include <linux/string.h>
158 +#include <linux/types.h>
159 +#include <linux/init.h>
160 +#include <linux/stat.h>
161 +#include <linux/ctype.h>
162 +#include <linux/slab.h>
163 +#include <linux/limits.h>
164 +#include <linux/pci.h>
165 +#include <linux/proc_fs.h>
166 +#include <asm/edd.h>
167 +
168 +MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
169 +MODULE_DESCRIPTION("proc interface to BIOS EDD information");
170 +MODULE_LICENSE("GPL");
171 +
172 +#define EDD_VERSION "0.08 2003-Jan-05"
173 +#define EDD_DEVICE_NAME_SIZE 16
174 +#define REPORT_URL "http://domsch.com/linux/edd30/results.html"
175 +
176 +#define left (count - (p - page) - 1)
177 +
178 +static struct proc_dir_entry *bios_dir;
179 +
180 +struct attr_entry {
181 +       struct proc_dir_entry *entry;
182 +       struct list_head node;
183 +};
184 +
185 +struct edd_device {
186 +       char name[EDD_DEVICE_NAME_SIZE];
187 +       struct edd_info *info;
188 +       struct proc_dir_entry *dir;
189 +       struct list_head attr_list;
190 +};
191 +
192 +static struct edd_device *edd_devices[EDDMAXNR];
193 +
194 +struct edd_attribute {
195 +       char *name;
196 +       int (*show)(char *page, char **start, off_t off,
197 +                   int count, int *eof, void *data);
198 +       int (*test) (struct edd_device * edev);
199 +};
200 +
201 +#define EDD_DEVICE_ATTR(_name,_show,_test) \
202 +struct edd_attribute edd_attr_##_name = {      \
203 +       .name = __stringify(_name), \
204 +       .show   = _show,            \
205 +        .test   = _test,            \
206 +};
207 +
208 +static inline struct edd_info *
209 +edd_dev_get_info(struct edd_device *edev)
210 +{
211 +       return edev->info;
212 +}
213 +
214 +static inline void
215 +edd_dev_set_info(struct edd_device *edev, struct edd_info *info)
216 +{
217 +       edev->info = info;
218 +}
219 +
220 +static int
221 +proc_calc_metrics(char *page, char **start, off_t off,
222 +                 int count, int *eof, int len)
223 +{
224 +       if (len <= off+count) *eof = 1;
225 +       *start = page + off;
226 +       len -= off;
227 +       if (len>count) len = count;
228 +       if (len<0) len = 0;
229 +       return len;
230 +}
231 +
232 +static int
233 +edd_dump_raw_data(char *b, int count, void *data, int length)
234 +{
235 +       char *orig_b = b;
236 +       char hexbuf[80], ascbuf[20], *h, *a, c;
237 +       unsigned char *p = data;
238 +       unsigned long column = 0;
239 +       int length_printed = 0, d;
240 +       const char maxcolumn = 16;
241 +       while (length_printed < length && count > 0) {
242 +               h = hexbuf;
243 +               a = ascbuf;
244 +               for (column = 0;
245 +                    column < maxcolumn && length_printed < length; column++) {
246 +                       h += sprintf(h, "%02x ", (unsigned char) *p);
247 +                       if (!isprint(*p))
248 +                               c = '.';
249 +                       else
250 +                               c = *p;
251 +                       a += sprintf(a, "%c", c);
252 +                       p++;
253 +                       length_printed++;
254 +               }
255 +               /* pad out the line */
256 +               for (; column < maxcolumn; column++) {
257 +                       h += sprintf(h, "   ");
258 +                       a += sprintf(a, " ");
259 +               }
260 +               d = snprintf(b, count, "%s\t%s\n", hexbuf, ascbuf);
261 +               b += d;
262 +               count -= d;
263 +       }
264 +       return (b - orig_b);
265 +}
266 +
267 +static int
268 +edd_show_host_bus(char *page, char **start, off_t off, int count, int *eof, void *data)
269 +{
270 +       struct edd_info *info = data;
271 +       char *p = page;
272 +       int i;
273 +
274 +       if (!info || !page || off) {
275 +               return proc_calc_metrics(page, start, off, count, eof, 0);
276 +       }
277 +
278 +       for (i = 0; i < 4; i++) {
279 +               if (isprint(info->params.host_bus_type[i])) {
280 +                       p += snprintf(p, left, "%c", info->params.host_bus_type[i]);
281 +               } else {
282 +                       p += snprintf(p, left, " ");
283 +               }
284 +       }
285 +
286 +       if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
287 +               p += snprintf(p, left, "\tbase_address: %x\n",
288 +                            info->params.interface_path.isa.base_address);
289 +       } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
290 +                  !strncmp(info->params.host_bus_type, "PCI", 3)) {
291 +               p += snprintf(p, left,
292 +                            "\t%02x:%02x.%d  channel: %u\n",
293 +                            info->params.interface_path.pci.bus,
294 +                            info->params.interface_path.pci.slot,
295 +                            info->params.interface_path.pci.function,
296 +                            info->params.interface_path.pci.channel);
297 +       } else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
298 +                  !strncmp(info->params.host_bus_type, "XPRS", 4) ||
299 +                  !strncmp(info->params.host_bus_type, "HTPT", 4)) {
300 +               p += snprintf(p, left,
301 +                            "\tTBD: %llx\n",
302 +                            info->params.interface_path.ibnd.reserved);
303 +
304 +       } else {
305 +               p += snprintf(p, left, "\tunknown: %llx\n",
306 +                            info->params.interface_path.unknown.reserved);
307 +       }
308 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
309 +}
310 +
311 +static int
312 +edd_show_interface(char *page, char **start, off_t off, int count, int *eof, void *data)
313 +{
314 +       struct edd_info *info = data;
315 +       char *p = page;
316 +       int i;
317 +
318 +       if (!info || !page || off) {
319 +               return proc_calc_metrics(page, start, off, count, eof, 0);
320 +       }
321 +
322 +       for (i = 0; i < 8; i++) {
323 +               if (isprint(info->params.interface_type[i])) {
324 +                       p += snprintf(p, left, "%c", info->params.interface_type[i]);
325 +               } else {
326 +                       p += snprintf(p, left, " ");
327 +               }
328 +       }
329 +       if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
330 +               p += snprintf(p, left, "\tdevice: %u  lun: %u\n",
331 +                            info->params.device_path.atapi.device,
332 +                            info->params.device_path.atapi.lun);
333 +       } else if (!strncmp(info->params.interface_type, "ATA", 3)) {
334 +               p += snprintf(p, left, "\tdevice: %u\n",
335 +                            info->params.device_path.ata.device);
336 +       } else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
337 +               p += snprintf(p, left, "\tid: %u  lun: %llu\n",
338 +                            info->params.device_path.scsi.id,
339 +                            info->params.device_path.scsi.lun);
340 +       } else if (!strncmp(info->params.interface_type, "USB", 3)) {
341 +               p += snprintf(p, left, "\tserial_number: %llx\n",
342 +                            info->params.device_path.usb.serial_number);
343 +       } else if (!strncmp(info->params.interface_type, "1394", 4)) {
344 +               p += snprintf(p, left, "\teui: %llx\n",
345 +                            info->params.device_path.i1394.eui);
346 +       } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
347 +               p += snprintf(p, left, "\twwid: %llx lun: %llx\n",
348 +                            info->params.device_path.fibre.wwid,
349 +                            info->params.device_path.fibre.lun);
350 +       } else if (!strncmp(info->params.interface_type, "I2O", 3)) {
351 +               p += snprintf(p, left, "\tidentity_tag: %llx\n",
352 +                            info->params.device_path.i2o.identity_tag);
353 +       } else if (!strncmp(info->params.interface_type, "RAID", 4)) {
354 +               p += snprintf(p, left, "\tidentity_tag: %x\n",
355 +                            info->params.device_path.raid.array_number);
356 +       } else if (!strncmp(info->params.interface_type, "SATA", 4)) {
357 +               p += snprintf(p, left, "\tdevice: %u\n",
358 +                            info->params.device_path.sata.device);
359 +       } else {
360 +               p += snprintf(p, left, "\tunknown: %llx %llx\n",
361 +                            info->params.device_path.unknown.reserved1,
362 +                            info->params.device_path.unknown.reserved2);
363 +       }
364 +
365 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
366 +}
367 +
368 +/**
369 + * edd_show_raw_data() - unparses EDD information, returned to user-space
370 + *
371 + * Returns: number of bytes written, or 0 on failure
372 + */
373 +static int
374 +edd_show_raw_data(char *page, char **start, off_t off, int count, int *eof, void *data)
375 +{
376 +       struct edd_info *info = data;
377 +       char *p = page;
378 +       int i, warn_padding = 0, nonzero_path = 0,
379 +               len = sizeof (*info) - 4;
380 +       uint8_t checksum = 0, c = 0;
381 +       if (!info || !page || off) {
382 +               return proc_calc_metrics(page, start, off, count, eof, 0);
383 +       }
384 +
385 +       if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
386 +               len = info->params.length;
387 +
388 +       p += snprintf(p, left, "int13 fn48 returned data:\n\n");
389 +       p += edd_dump_raw_data(p, left, ((char *) info) + 4, len);
390 +
391 +       /* Spec violation.  Adaptec AIC7899 returns 0xDDBE
392 +          here, when it should be 0xBEDD.
393 +        */
394 +       p += snprintf(p, left, "\n");
395 +       if (info->params.key == 0xDDBE) {
396 +               p += snprintf(p, left,
397 +                            "Warning: Spec violation.  Key should be 0xBEDD, is 0xDDBE\n");
398 +       }
399 +
400 +       if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
401 +               goto out;
402 +       }
403 +
404 +       for (i = 30; i <= 73; i++) {
405 +               c = *(((uint8_t *) info) + i + 4);
406 +               if (c)
407 +                       nonzero_path++;
408 +               checksum += c;
409 +       }
410 +
411 +       if (checksum) {
412 +               p += snprintf(p, left,
413 +                            "Warning: Spec violation.  Device Path checksum invalid.\n");
414 +       }
415 +
416 +       if (!nonzero_path) {
417 +               p += snprintf(p, left, "Error: Spec violation.  Empty device path.\n");
418 +               goto out;
419 +       }
420 +
421 +       for (i = 0; i < 4; i++) {
422 +               if (!isprint(info->params.host_bus_type[i])) {
423 +                       warn_padding++;
424 +               }
425 +       }
426 +       for (i = 0; i < 8; i++) {
427 +               if (!isprint(info->params.interface_type[i])) {
428 +                       warn_padding++;
429 +               }
430 +       }
431 +
432 +       if (warn_padding) {
433 +               p += snprintf(p, left,
434 +                            "Warning: Spec violation.  Padding should be 0x20.\n");
435 +       }
436 +
437 +out:
438 +       p += snprintf(p, left, "\nPlease check %s\n", REPORT_URL);
439 +       p += snprintf(p, left, "to see if this device has been reported.  If not,\n");
440 +       p += snprintf(p, left, "please send the information requested there.\n");
441 +
442 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
443 +}
444 +
445 +static int
446 +edd_show_version(char *page, char **start, off_t off, int count, int *eof, void *data)
447 +{
448 +       struct edd_info *info = data;
449 +       char *p = page;
450 +       if (!info || !page || off) {
451 +               return proc_calc_metrics(page, start, off, count, eof, 0);
452 +       }
453 +
454 +       p += snprintf(p, left, "0x%02x\n", info->version);
455 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
456 +}
457 +
458 +static int
459 +edd_show_extensions(char *page, char **start, off_t off, int count, int *eof, void *data)
460 +{
461 +       struct edd_info *info = data;
462 +       char *p = page;
463 +       if (!info || !page || off) {
464 +               return proc_calc_metrics(page, start, off, count, eof, 0);
465 +       }
466 +
467 +       if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
468 +               p += snprintf(p, left, "Fixed disk access\n");
469 +       }
470 +       if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
471 +               p += snprintf(p, left, "Device locking and ejecting\n");
472 +       }
473 +       if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
474 +               p += snprintf(p, left, "Enhanced Disk Drive support\n");
475 +       }
476 +       if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
477 +               p += snprintf(p, left, "64-bit extensions\n");
478 +       }
479 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
480 +}
481 +
482 +static int
483 +edd_show_info_flags(char *page, char **start, off_t off, int count, int *eof, void *data)
484 +{
485 +       struct edd_info *info = data;
486 +       char *p = page;
487 +       if (!info || !page || off) {
488 +               return proc_calc_metrics(page, start, off, count, eof, 0);
489 +       }
490 +
491 +       if (info->params.info_flags & EDD_INFO_DMA_BOUNDRY_ERROR_TRANSPARENT)
492 +               p += snprintf(p, left, "DMA boundry error transparent\n");
493 +       if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
494 +               p += snprintf(p, left, "geometry valid\n");
495 +       if (info->params.info_flags & EDD_INFO_REMOVABLE)
496 +               p += snprintf(p, left, "removable\n");
497 +       if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
498 +               p += snprintf(p, left, "write verify\n");
499 +       if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
500 +               p += snprintf(p, left, "media change notification\n");
501 +       if (info->params.info_flags & EDD_INFO_LOCKABLE)
502 +               p += snprintf(p, left, "lockable\n");
503 +       if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
504 +               p += snprintf(p, left, "no media present\n");
505 +       if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
506 +               p += snprintf(p, left, "use int13 fn50\n");
507 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
508 +}
509 +
510 +static int
511 +edd_show_default_cylinders(char *page, char **start, off_t off, int count, int *eof, void *data)
512 +{
513 +       struct edd_info *info = data;
514 +       char *p = page;
515 +       if (!info || !page || off) {
516 +               return proc_calc_metrics(page, start, off, count, eof, 0);
517 +       }
518 +
519 +       p += snprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
520 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
521 +}
522 +
523 +static int
524 +edd_show_default_heads(char *page, char **start, off_t off, int count, int *eof, void *data)
525 +{
526 +       struct edd_info *info = data;
527 +       char *p = page;
528 +       if (!info || !page || off) {
529 +               return proc_calc_metrics(page, start, off, count, eof, 0);
530 +       }
531 +
532 +       p += snprintf(p, left, "0x%x\n", info->params.num_default_heads);
533 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
534 +}
535 +
536 +static int
537 +edd_show_default_sectors_per_track(char *page, char **start, off_t off, int count, int *eof, void *data)
538 +{
539 +       struct edd_info *info = data;
540 +       char *p = page;
541 +       if (!info || !page || off) {
542 +               return proc_calc_metrics(page, start, off, count, eof, 0);
543 +       }
544 +
545 +       p += snprintf(p, left, "0x%x\n", info->params.sectors_per_track);
546 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
547 +}
548 +
549 +static int
550 +edd_show_sectors(char *page, char **start, off_t off, int count, int *eof, void *data)
551 +{
552 +       struct edd_info *info = data;
553 +       char *p = page;
554 +       if (!info || !page || off) {
555 +               return proc_calc_metrics(page, start, off, count, eof, 0);
556 +       }
557 +
558 +       p += snprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
559 +       return proc_calc_metrics(page, start, off, count, eof, (p - page));
560 +}
561 +
562 +static int
563 +edd_has_default_cylinders(struct edd_device *edev)
564 +{
565 +       struct edd_info *info = edd_dev_get_info(edev);
566 +       if (!edev || !info)
567 +               return 0;
568 +       return info->params.num_default_cylinders > 0;
569 +}
570 +
571 +static int
572 +edd_has_default_heads(struct edd_device *edev)
573 +{
574 +       struct edd_info *info = edd_dev_get_info(edev);
575 +       if (!edev || !info)
576 +               return 0;
577 +       return info->params.num_default_heads > 0;
578 +}
579 +
580 +static int
581 +edd_has_default_sectors_per_track(struct edd_device *edev)
582 +{
583 +       struct edd_info *info = edd_dev_get_info(edev);
584 +       if (!edev || !info)
585 +               return 0;
586 +       return info->params.sectors_per_track > 0;
587 +}
588 +
589 +static int
590 +edd_has_edd30(struct edd_device *edev)
591 +{
592 +       struct edd_info *info = edd_dev_get_info(edev);
593 +       int i, nonzero_path = 0;
594 +       char c;
595 +
596 +       if (!edev || !info)
597 +               return 0;
598 +
599 +       if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
600 +               return 0;
601 +       }
602 +
603 +       for (i = 30; i <= 73; i++) {
604 +               c = *(((uint8_t *) info) + i + 4);
605 +               if (c) {
606 +                       nonzero_path++;
607 +                       break;
608 +               }
609 +       }
610 +       if (!nonzero_path) {
611 +               return 0;
612 +       }
613 +
614 +       return 1;
615 +}
616 +
617 +static EDD_DEVICE_ATTR(raw_data, edd_show_raw_data, NULL);
618 +static EDD_DEVICE_ATTR(version, edd_show_version, NULL);
619 +static EDD_DEVICE_ATTR(extensions, edd_show_extensions, NULL);
620 +static EDD_DEVICE_ATTR(info_flags, edd_show_info_flags, NULL);
621 +static EDD_DEVICE_ATTR(sectors, edd_show_sectors, NULL);
622 +static EDD_DEVICE_ATTR(default_cylinders, edd_show_default_cylinders,
623 +                      edd_has_default_cylinders);
624 +static EDD_DEVICE_ATTR(default_heads, edd_show_default_heads,
625 +                      edd_has_default_heads);
626 +static EDD_DEVICE_ATTR(default_sectors_per_track, 
627 +                      edd_show_default_sectors_per_track,
628 +                      edd_has_default_sectors_per_track);
629 +static EDD_DEVICE_ATTR(interface, edd_show_interface,edd_has_edd30);
630 +static EDD_DEVICE_ATTR(host_bus, edd_show_host_bus, edd_has_edd30);
631 +
632 +static struct edd_attribute *def_attrs[] = {
633 +       &edd_attr_raw_data,
634 +       &edd_attr_version,
635 +       &edd_attr_extensions,
636 +       &edd_attr_info_flags,
637 +       &edd_attr_sectors,
638 +       &edd_attr_default_cylinders,
639 +       &edd_attr_default_heads,
640 +       &edd_attr_default_sectors_per_track,
641 +       &edd_attr_interface,
642 +       &edd_attr_host_bus,
643 +       NULL,
644 +};
645 +
646 +static inline void
647 +edd_device_unregister(struct edd_device *edev)
648 +{
649 +       struct list_head *pos, *next;
650 +       struct attr_entry *ae;
651 +
652 +       list_for_each_safe(pos, next, &edev->attr_list) {
653 +               ae = list_entry(pos, struct attr_entry, node);
654 +               remove_proc_entry(ae->entry->name, edev->dir);
655 +               list_del(&ae->node);
656 +               kfree(ae);
657 +       }
658 +
659 +       remove_proc_entry(edev->dir->name, bios_dir);
660 +}
661 +
662 +static int
663 +edd_populate_dir(struct edd_device *edev)
664 +{
665 +       struct edd_attribute *attr;
666 +       struct attr_entry *ae;
667 +       int i;
668 +       int error = 0;
669 +
670 +       for (i = 0; (attr=def_attrs[i]); i++) {
671 +               if (!attr->test || (attr->test && attr->test(edev))) {
672 +                       ae = kmalloc(sizeof (*ae), GFP_KERNEL);
673 +                       if (ae == NULL) {
674 +                               error = 1;
675 +                               break;
676 +                       }
677 +                       INIT_LIST_HEAD(&ae->node);
678 +                       ae->entry = 
679 +                               create_proc_read_entry(attr->name, 0444,
680 +                                                      edev->dir, attr->show,
681 +                                                      edd_dev_get_info(edev));                 
682 +                       if (ae->entry == NULL) {
683 +                               error = 1;
684 +                               break;
685 +                       }
686 +                       list_add(&ae->node, &edev->attr_list);
687 +               }
688 +       }
689 +
690 +       if (error)
691 +               return error;
692 +
693 +       return 0;
694 +}
695 +
696 +static int
697 +edd_make_dir(struct edd_device *edev)
698 +{
699 +       int error=1;
700 +
701 +       edev->dir = proc_mkdir(edev->name, bios_dir);
702 +       if (edev->dir != NULL) {
703 +               edev->dir->mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
704 +               error = edd_populate_dir(edev);
705 +       }
706 +       return error;
707 +}
708 +
709 +static int
710 +edd_device_register(struct edd_device *edev, int i)
711 +{
712 +       int error;
713 +
714 +       if (!edev)
715 +               return 1;
716 +       memset(edev, 0, sizeof (*edev));
717 +       INIT_LIST_HEAD(&edev->attr_list);
718 +       edd_dev_set_info(edev, &edd[i]);
719 +       snprintf(edev->name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
720 +                edd[i].device);
721 +       error = edd_make_dir(edev);
722 +       return error;
723 +}
724 +
725 +/**
726 + * edd_init() - creates driverfs tree of EDD data
727 + *
728 + * This assumes that eddnr and edd were
729 + * assigned in setup.c already.
730 + */
731 +static int __init
732 +edd_init(void)
733 +{
734 +       unsigned int i;
735 +       int rc = 0;
736 +       struct edd_device *edev;
737 +
738 +       printk(KERN_INFO "BIOS EDD facility v%s, %d devices found\n",
739 +              EDD_VERSION, eddnr);
740 +
741 +       if (!eddnr) {
742 +               printk(KERN_INFO "EDD information not available.\n");
743 +               return 1;
744 +       }
745 +
746 +       bios_dir = proc_mkdir("bios", NULL);
747 +       if (bios_dir == NULL)
748 +               return 1;
749 +
750 +       for (i = 0; i < eddnr && i < EDDMAXNR && !rc; i++) {
751 +               edev = kmalloc(sizeof (*edev), GFP_KERNEL);
752 +               if (!edev) {
753 +                       rc = 1;
754 +                       break;
755 +               }
756 +
757 +               rc = edd_device_register(edev, i);
758 +               if (rc) {
759 +                       break;
760 +               }
761 +               edd_devices[i] = edev;
762 +       }
763 +
764 +       if (rc) {
765 +               for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
766 +                       if ((edev = edd_devices[i])) {
767 +                               edd_device_unregister(edev);
768 +                               kfree(edev);
769 +                       }
770 +               }
771 +               
772 +               remove_proc_entry(bios_dir->name, NULL);
773 +       }
774 +       
775 +       return rc;
776 +}
777 +
778 +static void __exit
779 +edd_exit(void)
780 +{
781 +       int i;
782 +       struct edd_device *edev;
783 +
784 +       for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
785 +               if ((edev = edd_devices[i])) {
786 +                       edd_device_unregister(edev);
787 +                       kfree(edev);
788 +               }
789 +       }
790 +
791 +       remove_proc_entry(bios_dir->name, NULL);
792 +}
793 +
794 +module_init(edd_init);
795 +module_exit(edd_exit);
796 diff -urNp linux-651/arch/i386/kernel/i386_ksyms.c linux-660/arch/i386/kernel/i386_ksyms.c
797 --- linux-651/arch/i386/kernel/i386_ksyms.c     
798 +++ linux-660/arch/i386/kernel/i386_ksyms.c     
799 @@ -28,6 +28,7 @@
800  #include <asm/desc.h>
801  #include <asm/pgtable.h>
802  #include <asm/pgalloc.h>
803 +#include <asm/edd.h>
804  
805  extern void dump_thread(struct pt_regs *, struct user *);
806  extern spinlock_t rtc_lock;
807 @@ -183,3 +184,8 @@ EXPORT_SYMBOL(is_sony_vaio_laptop);
808  #ifdef CONFIG_MULTIQUAD
809  EXPORT_SYMBOL(xquad_portio);
810  #endif
811 +
812 +#ifdef CONFIG_EDD_MODULE
813 +EXPORT_SYMBOL(edd);
814 +EXPORT_SYMBOL(eddnr);
815 +#endif
816 diff -urNp linux-651/arch/i386/kernel/Makefile linux-660/arch/i386/kernel/Makefile
817 --- linux-651/arch/i386/kernel/Makefile 
818 +++ linux-660/arch/i386/kernel/Makefile 
819 @@ -40,5 +40,6 @@ obj-$(CONFIG_SMP)             += smp.o smpboot.o tr
820  obj-$(CONFIG_X86_LOCAL_APIC)   += mpparse.o apic.o nmi.o
821  obj-$(CONFIG_X86_IO_APIC)      += io_apic.o acpitable.o
822  obj-$(CONFIG_X86_VISWS_APIC)   += visws_apic.o
823 +obj-$(CONFIG_EDD)              += edd.o
824  
825  include $(TOPDIR)/Rules.make
826 diff -urNp linux-651/arch/i386/kernel/setup.c linux-660/arch/i386/kernel/setup.c
827 --- linux-651/arch/i386/kernel/setup.c  
828 +++ linux-660/arch/i386/kernel/setup.c  
829 @@ -115,6 +115,7 @@
830  #include <asm/dma.h>
831  #include <asm/mpspec.h>
832  #include <asm/mmu_context.h>
833 +#include <asm/edd.h>
834  /*
835   * Machine setup..
836   */
837 @@ -193,6 +194,8 @@ int enable_acpi_smp_table;
838  #define KERNEL_START (*(unsigned long *) (PARAM+0x214))
839  #define INITRD_START (*(unsigned long *) (PARAM+0x218))
840  #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
841 +#define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
842 +#define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
843  #define COMMAND_LINE ((char *) (PARAM+2048))
844  #define COMMAND_LINE_SIZE 256
845  
846 @@ -693,6 +696,23 @@ static int __init copy_e820_map(struct e
847         return 0;
848  }
849  
850 +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
851 +unsigned char eddnr;
852 +struct edd_info edd[EDDNR];
853 +/**
854 + * copy_edd() - Copy the BIOS EDD information
855 + *              from empty_zero_page into a safe place.
856 + *
857 + */
858 +static inline void copy_edd(void)
859 +{
860 +     eddnr = EDD_NR;
861 +     memcpy(edd, EDD_BUF, sizeof(edd));
862 +}
863 +#else
864 +#define copy_edd() do {} while (0)
865 +#endif
866 +
867  /*
868   * Do NOT EVER look at the BIOS memory size location.
869   * It does not work on many machines.
870 @@ -1105,6 +1125,7 @@ void __init setup_arch(char **cmdline_p)
871         rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
872  #endif
873         setup_memory_region();
874 +       copy_edd();
875  
876         if (!MOUNT_ROOT_RDONLY)
877                 root_mountflags &= ~MS_RDONLY;
878 diff -urNp linux-651/Documentation/Configure.help linux-660/Documentation/Configure.help
879 --- linux-651/Documentation/Configure.help      
880 +++ linux-660/Documentation/Configure.help      
881 @@ -19022,6 +19022,15 @@ CONFIG_X86_CPUID
882    <file:Documentation/modules.txt>. The module will be called
883    cpuid.o
884  
885 +x86 BIOS Enhanced Disk Drive support
886 +CONFIG_EDD
887 +  Say Y or M here if you want to enable BIOS Enhanced Disk Drive
888 +  Services real mode BIOS calls to determine which disk
889 +  BIOS tries boot from.  This information is then exported via /proc.
890 +
891 +  This option is experimental, but believed to be safe,
892 +  and most disk controller BIOS vendors do not yet implement this feature.
893 +
894  SBC-60XX Watchdog Timer
895  CONFIG_60XX_WDT
896   This driver can be used with the watchdog timer found on some
897 diff -urNp linux-651/Documentation/i386/zero-page.txt linux-660/Documentation/i386/zero-page.txt
898 --- linux-651/Documentation/i386/zero-page.txt  1999-08-30 19:47:02.000000000 +0200
899 +++ linux-660/Documentation/i386/zero-page.txt  
900 @@ -31,6 +31,7 @@ Offset        Type            Description
901  
902  0x1e0  unsigned long   ALT_MEM_K, alternative mem check, in Kb
903  0x1e8  char            number of entries in E820MAP (below)
904 +0x1e9  unsigned char   number of entries in EDDBUF (below)
905  0x1f1  char            size of setup.S, number of sectors
906  0x1f2  unsigned short  MOUNT_ROOT_RDONLY (if !=0)
907  0x1f4  unsigned short  size of compressed kernel-part in the
908 @@ -66,6 +67,7 @@ Offset        Type            Description
909  0x220  4 bytes         (setup.S)
910  0x224  unsigned short  setup.S heap end pointer
911  0x2d0 - 0x600          E820MAP
912 +0x600 - 0x7D4          EDDBUF (setup.S)
913  
914  0x800  string, 2K max  COMMAND_LINE, the kernel commandline as
915                         copied using CL_OFFSET.
916 diff -urNp linux-651/include/asm-i386/edd.h linux-660/include/asm-i386/edd.h
917 --- linux-651/include/asm-i386/edd.h    1970-01-01 01:00:00.000000000 +0100
918 +++ linux-660/include/asm-i386/edd.h    
919 @@ -0,0 +1,172 @@
920 +/*
921 + * linux/include/asm-i386/edd.h
922 + *  Copyright (C) 2002 Dell Computer Corporation
923 + *  by Matt Domsch <Matt_Domsch@dell.com>
924 + *
925 + * structures and definitions for the int 13h, ax={41,48}h
926 + * BIOS Enhanced Disk Drive Services
927 + * This is based on the T13 group document D1572 Revision 0 (August 14 2002)
928 + * available at http://www.t13.org/docs2002/d1572r0.pdf.  It is
929 + * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf
930 + *
931 + * In a nutshell, arch/i386/boot/setup.S populates a scratch table
932 + * in the empty_zero_block that contains a list of BIOS-enumerated
933 + * boot devices.
934 + * In arch/i386/kernel/setup.c, this information is
935 + * transferred into the edd structure, and in arch/i386/kernel/edd.c, that
936 + * information is used to identify BIOS boot disk.  The code in setup.S
937 + * is very sensitive to the size of these structures.
938 + *
939 + * This program is free software; you can redistribute it and/or modify
940 + * it under the terms of the GNU General Public License v2.0 as published by
941 + * the Free Software Foundation
942 + *
943 + * This program is distributed in the hope that it will be useful,
944 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
945 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
946 + * GNU General Public License for more details.
947 + *
948 + */
949 +#ifndef _ASM_I386_EDD_H
950 +#define _ASM_I386_EDD_H
951 +
952 +#define EDDNR 0x1e9            /* addr of number of edd_info structs at EDDBUF
953 +                                  in empty_zero_block - treat this as 1 byte  */
954 +#define EDDBUF 0x600           /* addr of edd_info structs in empty_zero_block */
955 +#define EDDMAXNR 6             /* number of edd_info structs starting at EDDBUF  */
956 +#define EDDEXTSIZE 4           /* change these if you muck with the structures */
957 +#define EDDPARMSIZE 74
958 +#define CHECKEXTENSIONSPRESENT 0x41
959 +#define GETDEVICEPARAMETERS 0x48
960 +#define EDDMAGIC1 0x55AA
961 +#define EDDMAGIC2 0xAA55
962 +
963 +#ifndef __ASSEMBLY__
964 +
965 +#define EDD_EXT_FIXED_DISK_ACCESS           (1 << 0)
966 +#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1)
967 +#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2)
968 +#define EDD_EXT_64BIT_EXTENSIONS            (1 << 3)
969 +
970 +#define EDD_INFO_DMA_BOUNDRY_ERROR_TRANSPARENT (1 << 0)
971 +#define EDD_INFO_GEOMETRY_VALID                (1 << 1)
972 +#define EDD_INFO_REMOVABLE                     (1 << 2)
973 +#define EDD_INFO_WRITE_VERIFY                  (1 << 3)
974 +#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION     (1 << 4)
975 +#define EDD_INFO_LOCKABLE                      (1 << 5)
976 +#define EDD_INFO_NO_MEDIA_PRESENT              (1 << 6)
977 +#define EDD_INFO_USE_INT13_FN50                (1 << 7)
978 +
979 +struct edd_device_params {
980 +       u16 length;
981 +       u16 info_flags;
982 +       u32 num_default_cylinders;
983 +       u32 num_default_heads;
984 +       u32 sectors_per_track;
985 +       u64 number_of_sectors;
986 +       u16 bytes_per_sector;
987 +       u32 dpte_ptr;           /* 0xFFFFFFFF for our purposes */
988 +       u16 key;                /* = 0xBEDD */
989 +       u8 device_path_info_length;     /* = 44 */
990 +       u8 reserved2;
991 +       u16 reserved3;
992 +       u8 host_bus_type[4];
993 +       u8 interface_type[8];
994 +       union {
995 +               struct {
996 +                       u16 base_address;
997 +                       u16 reserved1;
998 +                       u32 reserved2;
999 +               } __attribute__ ((packed)) isa;
1000 +               struct {
1001 +                       u8 bus;
1002 +                       u8 slot;
1003 +                       u8 function;
1004 +                       u8 channel;
1005 +                       u32 reserved;
1006 +               } __attribute__ ((packed)) pci;
1007 +               /* pcix is same as pci */
1008 +               struct {
1009 +                       u64 reserved;
1010 +               } __attribute__ ((packed)) ibnd;
1011 +               struct {
1012 +                       u64 reserved;
1013 +               } __attribute__ ((packed)) xprs;
1014 +               struct {
1015 +                       u64 reserved;
1016 +               } __attribute__ ((packed)) htpt;
1017 +               struct {
1018 +                       u64 reserved;
1019 +               } __attribute__ ((packed)) unknown;
1020 +       } interface_path;
1021 +       union {
1022 +               struct {
1023 +                       u8 device;
1024 +                       u8 reserved1;
1025 +                       u16 reserved2;
1026 +                       u32 reserved3;
1027 +                       u64 reserved4;
1028 +               } __attribute__ ((packed)) ata;
1029 +               struct {
1030 +                       u8 device;
1031 +                       u8 lun;
1032 +                       u8 reserved1;
1033 +                       u8 reserved2;
1034 +                       u32 reserved3;
1035 +                       u64 reserved4;
1036 +               } __attribute__ ((packed)) atapi;
1037 +               struct {
1038 +                       u16 id;
1039 +                       u64 lun;
1040 +                       u16 reserved1;
1041 +                       u32 reserved2;
1042 +               } __attribute__ ((packed)) scsi;
1043 +               struct {
1044 +                       u64 serial_number;
1045 +                       u64 reserved;
1046 +               } __attribute__ ((packed)) usb;
1047 +               struct {
1048 +                       u64 eui;
1049 +                       u64 reserved;
1050 +               } __attribute__ ((packed)) i1394;
1051 +               struct {
1052 +                       u64 wwid;
1053 +                       u64 lun;
1054 +               } __attribute__ ((packed)) fibre;
1055 +               struct {
1056 +                       u64 identity_tag;
1057 +                       u64 reserved;
1058 +               } __attribute__ ((packed)) i2o;
1059 +               struct {
1060 +                       u32 array_number;
1061 +                       u32 reserved1;
1062 +                       u64 reserved2;
1063 +               } __attribute((packed)) raid;
1064 +               struct {
1065 +                       u8 device;
1066 +                       u8 reserved1;
1067 +                       u16 reserved2;
1068 +                       u32 reserved3;
1069 +                       u64 reserved4;
1070 +               } __attribute__ ((packed)) sata;
1071 +               struct {
1072 +                       u64 reserved1;
1073 +                       u64 reserved2;
1074 +               } __attribute__ ((packed)) unknown;
1075 +       } device_path;
1076 +       u8 reserved4;
1077 +       u8 checksum;
1078 +} __attribute__ ((packed));
1079 +
1080 +struct edd_info {
1081 +       u8 device;
1082 +       u8 version;
1083 +       u16 interface_support;
1084 +       struct edd_device_params params;
1085 +} __attribute__ ((packed));
1086 +
1087 +extern struct edd_info edd[EDDNR];
1088 +extern unsigned char eddnr;
1089 +#endif                         /*!__ASSEMBLY__ */
1090 +
1091 +#endif                         /* _ASM_I386_EDD_H */
This page took 0.496906 seconds and 3 git commands to generate.