Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S264059AbUCPQmB (ORCPT ); Tue, 16 Mar 2004 11:42:01 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S263134AbUCPQlH (ORCPT ); Tue, 16 Mar 2004 11:41:07 -0500 Received: from linux.us.dell.com ([143.166.224.162]:18376 "EHLO lists.us.dell.com") by vger.kernel.org with ESMTP id S263995AbUCPQYy (ORCPT ); Tue, 16 Mar 2004 11:24:54 -0500 Date: Tue, 16 Mar 2004 10:23:44 -0600 From: Matt Domsch To: ak@suse.de, akpm@osdl.org, davej@redhat.com, hpa@zytor.com Cc: linux-kernel@vger.kernel.org Subject: [RFC][PATCH] let EDD work on x86-64 too Message-ID: <20040316162344.GA20289@lists.us.dell.com> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="VS++wcV0S1rZb1Fb" Content-Disposition: inline User-Agent: Mutt/1.4.1i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 90646 Lines: 2872 --VS++wcV0S1rZb1Fb Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Andi, I'm proposing allowing my BIOS Enhanced Disk Drive (EDD) code to work on x86-64 as it does on x86 today. The patch below moves some files around out of arch/i386/kernel and include/asm-i386 into more generic locations, and allows EDD to work. I've tested this against BK-cur= rent (from my POV it's 2.6.4 plus the edd-legacychs patch Andrew forwarded to Linus and is now in BK); I see there will be conflicts with the empty_zero_page-cleanup.patch which is in -mm right now - they're just comment conflicts, but I'll need to clean that up once it's in BK. Feedback welcome. Thanks, Matt --=20 Matt Domsch Sr. Software Engineer, Lead Engineer Dell Linux Solutions linux.dell.com & www.dell.com/linux Linux on Dell mailing lists @ http://lists.us.dell.com You can import this changeset into BK by piping this whole message to '| bk receive [path to repository]' or apply the patch as usual. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ChangeSet@1.1631, 2004-03-16 10:02:58-06:00, Matt_Domsch@dell.com EDD: perform EDD calls on x86_64, move edd.c to new dir drivers/firmware =20 This patch allows the BIOS EDD code, previously built only for x86, to be built and used on x86_64 as well, with minimal duplication of code. =20 arch/i386/kernel/edd.c moves to drivers/firmware/edd.c include/asm-i386/edd.h moves to include/linux/edd.h EDD assembly code moves from arch/i386/boot/setup.S into arch/i386/boot/e= dd.S and is #included into setup.S for both i386 and x86_64 arches. arch/i386/kernel/edd.c | 837 ------------------------------= ----- b/Documentation/x86_64/zero-page.txt | 84 +++ b/arch/i386/Kconfig | 11=20 b/arch/i386/boot/edd.S | 127 +++++ b/arch/i386/boot/setup.S | 125 ----- b/arch/i386/kernel/Makefile | 1=20 b/arch/i386/kernel/setup.c | 2=20 b/arch/x86_64/Kconfig | 2=20 b/arch/x86_64/boot/setup.S | 2=20 b/arch/x86_64/defconfig | 1=20 b/arch/x86_64/kernel/setup.c | 26 + b/drivers/Makefile | 1=20 b/drivers/firmware/Kconfig | 19=20 b/drivers/firmware/Makefile | 4=20 b/drivers/firmware/edd.c | 837 ++++++++++++++++++++++++++++++= +++++ b/include/asm-x86_64/bootsetup.h | 3=20 b/include/linux/edd.h | 181 +++++++ include/asm-i386/edd.h | 180 ------- 18 files changed, 1290 insertions, 1153 deletions diff -Nru a/Documentation/x86_64/zero-page.txt b/Documentation/x86_64/zero-= page.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/x86_64/zero-page.txt Tue Mar 16 10:03:36 2004 @@ -0,0 +1,84 @@ +Summary of empty_zero_page layout (kernel point of view) + ( collected by Hans Lermen and Martin Mares ) +=20 +The contents of empty_zero_page are used to pass parameters from the +16-bit realmode code of the kernel to the 32-bit part. References/settings +to it mainly are in: + + arch/i386/boot/setup.S + arch/i386/boot/video.S + arch/i386/kernel/head.S + arch/i386/kernel/setup.c +=20 + +Offset Type Description +------ ---- ----------- + 0 32 bytes struct screen_info, SCREEN_INFO + ATTENTION, overlaps the following !!! + 2 unsigned short EXT_MEM_K, extended memory size in Kb (from int 0x15) + 0x20 unsigned short CL_MAGIC, commandline magic number (=3D0xA33F) + 0x22 unsigned short CL_OFFSET, commandline offset + Address of commandline is calculated: + 0x90000 + contents of CL_OFFSET + (only taken, when CL_MAGIC =3D 0xA33F) + 0x40 20 bytes struct apm_bios_info, APM_BIOS_INFO + 0x60 16 bytes Intel SpeedStep (IST) BIOS support information + 0x80 16 bytes hd0-disk-parameter from intvector 0x41 + 0x90 16 bytes hd1-disk-parameter from intvector 0x46 + + 0xa0 16 bytes System description table truncated to 16 bytes. + ( struct sys_desc_table_struct ) + 0xb0 - 0x1c3 Free. Add more parameters here if you really need them. + +0x1c4 unsigned long EFI system table pointer +0x1c8 unsigned long EFI memory descriptor size +0x1cc unsigned long EFI memory descriptor version +0x1d0 unsigned long EFI memory descriptor map pointer +0x1d4 unsigned long EFI memory descriptor map size +0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb +0x1e8 char number of entries in E820MAP (below) +0x1e9 unsigned char number of entries in EDDBUF (below) +0x1f1 char size of setup.S, number of sectors +0x1f2 unsigned short MOUNT_ROOT_RDONLY (if !=3D0) +0x1f4 unsigned short size of compressed kernel-part in the + (b)zImage-file (in 16 byte units, rounded up) +0x1f6 unsigned short swap_dev (unused AFAIK) +0x1f8 unsigned short RAMDISK_FLAGS +0x1fa unsigned short VGA-Mode (old one) +0x1fc unsigned short ORIG_ROOT_DEV (high=3DMajor, low=3Dminor) +0x1ff char AUX_DEVICE_INFO + +0x200 short jump to start of setup code aka "reserved" field. +0x202 4 bytes Signature for SETUP-header, =3D"HdrS" +0x206 unsigned short Version number of header format + Current version is 0x0201... +0x208 8 bytes (used by setup.S for communication with boot loaders, + look there) +0x210 char LOADER_TYPE, =3D 0, old one + else it is set by the loader: + 0xTV: T=3D0 for LILO + 1 for Loadlin + 2 for bootsect-loader + 3 for SYSLINUX + 4 for ETHERBOOT + V =3D version +0x211 char loadflags: + bit0 =3D 1: kernel is loaded high (bzImage) + bit7 =3D 1: Heap and pointer (see below) set by boot + loader. +0x212 unsigned short (setup.S) +0x214 unsigned long KERNEL_START, where the loader started the kernel +0x218 unsigned long INITRD_START, address of loaded ramdisk image +0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image +0x220 4 bytes (setup.S) +0x224 unsigned short setup.S heap end pointer +0x2cc 4 bytes DISK80_SIG_BUFFER (setup.S) +0x2d0 - 0x600 E820MAP +0x600 - 0x7ff EDDBUF (setup.S) for disk signature read sector +0x600 - 0x7eb EDDBUF (setup.S) for edd data + +0x800 string, 2K max COMMAND_LINE, the kernel commandline as + copied using CL_OFFSET. + Note: this will be copied once more by setup.c + into a local buffer which is only 256 bytes long. + ( #define COMMAND_LINE_SIZE 256 ) diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Tue Mar 16 10:03:36 2004 +++ b/arch/i386/Kconfig Tue Mar 16 10:03:36 2004 @@ -637,16 +637,7 @@ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to /dev/cpu/31/cpuid. =20 -config EDD - tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTA= L)" - depends on EXPERIMENTAL - help - Say Y or M here if you want to enable BIOS Enhanced Disk Drive - Services real mode BIOS calls to determine which disk - BIOS tries boot from. This information is then exported via driverfs. - - This option is experimental, but believed to be safe, - and most disk controller BIOS vendors do not yet implement this feature. +source "drivers/firmware/Kconfig" =20 choice prompt "High Memory Support" diff -Nru a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/boot/edd.S Tue Mar 16 10:03:36 2004 @@ -0,0 +1,127 @@ +/* + * BIOS Enhanced Disk Drive support + * by Matt Domsch October 2002 + * conformant to T13 Committee www.t13.org + * projects 1572D, 1484D, 1386D, 1226DT + * disk signature read by Matt Domsch + * and Andrew Wilks September 2003 + * legacy CHS retreival by Patrick J. LoPresti + * March 2004 + */ + +#include + +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) +# Read the first sector of device 80h and store the 4-byte signature + movl $0xFFFFFFFF, %eax + movl %eax, (DISK80_SIG_BUFFER) # assume failure + movb $READ_SECTORS, %ah + movb $1, %al # read 1 sector + movb $0x80, %dl # from device 80 + movb $0, %dh # at head 0 + movw $1, %cx # cylinder 0, sector 0 + pushw %es + pushw %ds + popw %es + movw $EDDBUF, %bx + pushw %dx # work around buggy BIOSes + stc # work around buggy BIOSes + int $0x13 + sti # work around buggy BIOSes + popw %dx + jc disk_sig_done + movl (EDDBUF+MBR_SIG_OFFSET), %eax + movl %eax, (DISK80_SIG_BUFFER) # store success +disk_sig_done: + popw %es + +# Do the BIOS Enhanced Disk Drive calls +# This consists of two calls: +# int 13h ah=3D41h "Check Extensions Present" +# int 13h ah=3D48h "Get Device Parameters" +# int 13h ah=3D08h "Legacy Get Device Parameters" +# +# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our u= se +# in the empty_zero_page at EDDBUF. The first four bytes of which are +# used to store the device number, interface support map and version +# results from fn41. The next four bytes are used to store the legacy +# cylinders, heads, and sectors from fn08. The following 74 bytes are used= to +# store the results from fn48. Starting from device 80h, fn41, then fn48 +# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). +# Then the pointer is incremented to store the data for the next call. +# This repeats until either a device doesn't exist, or until EDDMAXNR +# devices have been stored. +# The one tricky part is that ds:si always points EDDEXTSIZE bytes into +# the structure, and the fn41 and fn08 results are stored at offsets +# from there. This removes the need to increment the pointer for +# every store, and leaves it ready for the fn48 call. +# A second one-byte buffer, EDDNR, in the empty_zero_page stores +# the number of BIOS devices which exist, up to EDDMAXNR. +# In setup.c, copy_edd() stores both empty_zero_page buffers away +# for later use, as they would get overwritten otherwise. +# This code is sensitive to the size of the structs in edd.h +edd_start: + # %ds points to the bootsector + # result buffer for fn48 + movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results + # kept just before that + movb $0, (EDDNR) # zero value at EDDNR + movb $0x80, %dl # BIOS device 0x80 + +edd_check_ext: + movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 + movw $EDDMAGIC1, %bx # magic + int $0x13 # make the call + jc edd_done # no more BIOS devices + + cmpw $EDDMAGIC2, %bx # is magic right? + jne edd_next # nope, next... + + movb %dl, %ds:-8(%si) # store device number + movb %ah, %ds:-7(%si) # store version + movw %cx, %ds:-6(%si) # store extensions + incb (EDDNR) # note that we stored something + +edd_get_device_params: + movw $EDDPARMSIZE, %ds:(%si) # put size + movw $0x0, %ds:2(%si) # work around buggy BIOSes + movb $GETDEVICEPARAMETERS, %ah # Function 48 + int $0x13 # make the call + # Don't check for fail return + # it doesn't matter. +edd_get_legacy_chs: + xorw %ax, %ax + movw %ax, %ds:-4(%si) + movw %ax, %ds:-2(%si) + # Ralf Brown's Interrupt List says to set ES:DI to + # 0000h:0000h "to guard against BIOS bugs" + pushw %es + movw %ax, %es + movw %ax, %di + pushw %dx # legacy call clobbers %dl + movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08 + int $0x13 # make the call + jc edd_legacy_done # failed + movb %cl, %al # Low 6 bits are max + andb $0x3F, %al # sector number + movb %al, %ds:-1(%si) # Record max sect + movb %dh, %ds:-2(%si) # Record max head number + movb %ch, %al # Low 8 bits of max cyl + shr $6, %cl + movb %cl, %ah # High 2 bits of max cyl + movw %ax, %ds:-4(%si) + +edd_legacy_done: + popw %dx + popw %es + movw %si, %ax # increment si + addw $EDDPARMSIZE+EDDEXTSIZE, %ax + movw %ax, %si + +edd_next: + incb %dl # increment to next device + cmpb $EDDMAXNR, (EDDNR) # Out of space? + jb edd_check_ext # keep looping + +edd_done: +#endif diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S --- a/arch/i386/boot/setup.S Tue Mar 16 10:03:36 2004 +++ b/arch/i386/boot/setup.S Tue Mar 16 10:03:36 2004 @@ -44,15 +44,6 @@ * * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes * by Robert Schwebel, December 2001 - * =20 - * BIOS Enhanced Disk Drive support - * by Matt Domsch October 2002 - * conformant to T13 Committee www.t13.org - * projects 1572D, 1484D, 1386D, 1226DT - * disk signature read by Matt Domsch - * and Andrew Wilks September 2003 - * legacy CHS retreival by Patrick J. LoPresti - * March 2004 */ =20 #include @@ -61,7 +52,6 @@ #include #include #include -#include =20 #include =09 /* Signature words to ensure LILO loaded us right */ @@ -581,120 +571,7 @@ done_apm_bios: #endif =20 -#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) -# Read the first sector of device 80h and store the 4-byte signature - movl $0xFFFFFFFF, %eax - movl %eax, (DISK80_SIG_BUFFER) # assume failure - movb $READ_SECTORS, %ah - movb $1, %al # read 1 sector - movb $0x80, %dl # from device 80 - movb $0, %dh # at head 0 - movw $1, %cx # cylinder 0, sector 0 - pushw %es - pushw %ds - popw %es - movw $EDDBUF, %bx - pushw %dx # work around buggy BIOSes - stc # work around buggy BIOSes - int $0x13 - sti # work around buggy BIOSes - popw %dx - jc disk_sig_done - movl (EDDBUF+MBR_SIG_OFFSET), %eax - movl %eax, (DISK80_SIG_BUFFER) # store success -disk_sig_done: - popw %es - -# Do the BIOS Enhanced Disk Drive calls -# This consists of two calls: -# int 13h ah=3D41h "Check Extensions Present" -# int 13h ah=3D48h "Get Device Parameters" -# int 13h ah=3D08h "Legacy Get Device Parameters" -# -# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our u= se -# in the empty_zero_page at EDDBUF. The first four bytes of which are -# used to store the device number, interface support map and version -# results from fn41. The next four bytes are used to store the legacy -# cylinders, heads, and sectors from fn08. The following 74 bytes are used= to -# store the results from fn48. Starting from device 80h, fn41, then fn48 -# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). -# Then the pointer is incremented to store the data for the next call. -# This repeats until either a device doesn't exist, or until EDDMAXNR -# devices have been stored. -# The one tricky part is that ds:si always points EDDEXTSIZE bytes into -# the structure, and the fn41 and fn08 results are stored at offsets -# from there. This removes the need to increment the pointer for -# every store, and leaves it ready for the fn48 call. -# A second one-byte buffer, EDDNR, in the empty_zero_page stores -# the number of BIOS devices which exist, up to EDDMAXNR. -# In setup.c, copy_edd() stores both empty_zero_page buffers away -# for later use, as they would get overwritten otherwise. -# This code is sensitive to the size of the structs in edd.h -edd_start: - # %ds points to the bootsector - # result buffer for fn48 - movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results - # kept just before that - movb $0, (EDDNR) # zero value at EDDNR - movb $0x80, %dl # BIOS device 0x80 - -edd_check_ext: - movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 - movw $EDDMAGIC1, %bx # magic - int $0x13 # make the call - jc edd_done # no more BIOS devices - - cmpw $EDDMAGIC2, %bx # is magic right? - jne edd_next # nope, next... - - movb %dl, %ds:-8(%si) # store device number - movb %ah, %ds:-7(%si) # store version - movw %cx, %ds:-6(%si) # store extensions - incb (EDDNR) # note that we stored something - -edd_get_device_params: - movw $EDDPARMSIZE, %ds:(%si) # put size - movw $0x0, %ds:2(%si) # work around buggy BIOSes - movb $GETDEVICEPARAMETERS, %ah # Function 48 - int $0x13 # make the call - # Don't check for fail return - # it doesn't matter. -edd_get_legacy_chs: - xorw %ax, %ax - movw %ax, %ds:-4(%si) - movw %ax, %ds:-2(%si) - # Ralf Brown's Interrupt List says to set ES:DI to - # 0000h:0000h "to guard against BIOS bugs" - pushw %es - movw %ax, %es - movw %ax, %di - pushw %dx # legacy call clobbers %dl - movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08 - int $0x13 # make the call - jc edd_legacy_done # failed - movb %cl, %al # Low 6 bits are max - andb $0x3F, %al # sector number - movb %al, %ds:-1(%si) # Record max sect - movb %dh, %ds:-2(%si) # Record max head number - movb %ch, %al # Low 8 bits of max cyl - shr $6, %cl - movb %cl, %ah # High 2 bits of max cyl - movw %ax, %ds:-4(%si) - -edd_legacy_done: - popw %dx - popw %es - movw %si, %ax # increment si - addw $EDDPARMSIZE+EDDEXTSIZE, %ax - movw %ax, %si - -edd_next: - incb %dl # increment to next device - cmpb $EDDMAXNR, (EDDNR) # Out of space? - jb edd_check_ext # keep looping - -edd_done: -#endif +#include "edd.S" =20 # Now we want to move to protected mode ... cmpw $0, %cs:realmode_swtch diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Tue Mar 16 10:03:36 2004 +++ b/arch/i386/kernel/Makefile Tue Mar 16 10:03:36 2004 @@ -25,7 +25,6 @@ obj-$(CONFIG_X86_IO_APIC) +=3D io_apic.o obj-$(CONFIG_X86_NUMAQ) +=3D numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) +=3D summit.o -obj-$(CONFIG_EDD) +=3D edd.o obj-$(CONFIG_MODULES) +=3D module.o obj-y +=3D sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) +=3D srat.o diff -Nru a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c --- a/arch/i386/kernel/edd.c Tue Mar 16 10:03:36 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,837 +0,0 @@ -/* - * linux/arch/i386/kernel/edd.c - * Copyright (C) 2002, 2003, 2004 Dell Inc. - * by Matt Domsch - * disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya - * legacy CHS by Patrick J. LoPresti - * - * BIOS Enhanced Disk Drive Services (EDD) - * conformant to T13 Committee www.t13.org - * projects 1572D, 1484D, 1386D, 1226DT - * - * This code takes information provided by BIOS EDD calls - * fn41 - Check Extensions Present and - * fn48 - Get Device Parametes with EDD extensions - * made in setup.S, copied to safe structures in setup.c, - * and presents it in sysfs. - * - * Please see http://domsch.com/linux/edd30/results.html for - * the list of BIOSs which have been reported to implement EDD. - * If you don't see yours listed, please send a report as described there. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published = by - * the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -/* - * Known issues: - * - refcounting of struct device objects could be improved. - * - * TODO: - * - Add IDE and USB disk device support - * - move edd.[ch] to better locations if/when one is decided - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* FIXME - this really belongs in include/scsi/scsi.h */ -#include <../drivers/scsi/scsi.h> -#include <../drivers/scsi/hosts.h> - -MODULE_AUTHOR("Matt Domsch "); -MODULE_DESCRIPTION("sysfs interface to BIOS EDD information"); -MODULE_LICENSE("GPL"); - -#define EDD_VERSION "0.13 2004-Mar-09" -#define EDD_DEVICE_NAME_SIZE 16 -#define REPORT_URL "http://linux.dell.com/edd/results.html" - -#define left (PAGE_SIZE - (p - buf) - 1) - -struct edd_device { - struct edd_info *info; - struct kobject kobj; -}; - -struct edd_attribute { - struct attribute attr; - ssize_t(*show) (struct edd_device * edev, char *buf); - int (*test) (struct edd_device * edev); -}; - -/* forward declarations */ -static int edd_dev_is_type(struct edd_device *edev, const char *type); -static struct pci_dev *edd_get_pci_dev(struct edd_device *edev); - -static struct edd_device *edd_devices[EDDMAXNR]; - -#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \ -struct edd_attribute edd_attr_##_name =3D { \ - .attr =3D {.name =3D __stringify(_name), .mode =3D _mode }, \ - .show =3D _show, \ - .test =3D _test, \ -}; - -static inline struct edd_info * -edd_dev_get_info(struct edd_device *edev) -{ - return edev->info; -} - -static inline void -edd_dev_set_info(struct edd_device *edev, struct edd_info *info) -{ - edev->info =3D info; -} - -#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr) -#define to_edd_device(obj) container_of(obj,struct edd_device,kobj) - -static ssize_t -edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) -{ - struct edd_device *dev =3D to_edd_device(kobj); - struct edd_attribute *edd_attr =3D to_edd_attr(attr); - ssize_t ret =3D 0; - - if (edd_attr->show) - ret =3D edd_attr->show(dev, buf); - return ret; -} - -static struct sysfs_ops edd_attr_ops =3D { - .show =3D edd_attr_show, -}; - -static ssize_t -edd_show_host_bus(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - int i; - - if (!edev || !info || !buf) { - return -EINVAL; - } - - for (i =3D 0; i < 4; i++) { - if (isprint(info->params.host_bus_type[i])) { - p +=3D scnprintf(p, left, "%c", info->params.host_bus_type[i]); - } else { - p +=3D scnprintf(p, left, " "); - } - } - - if (!strncmp(info->params.host_bus_type, "ISA", 3)) { - p +=3D scnprintf(p, left, "\tbase_address: %x\n", - info->params.interface_path.isa.base_address); - } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) || - !strncmp(info->params.host_bus_type, "PCI", 3)) { - p +=3D scnprintf(p, left, - "\t%02x:%02x.%d channel: %u\n", - info->params.interface_path.pci.bus, - info->params.interface_path.pci.slot, - info->params.interface_path.pci.function, - info->params.interface_path.pci.channel); - } else if (!strncmp(info->params.host_bus_type, "IBND", 4) || - !strncmp(info->params.host_bus_type, "XPRS", 4) || - !strncmp(info->params.host_bus_type, "HTPT", 4)) { - p +=3D scnprintf(p, left, - "\tTBD: %llx\n", - info->params.interface_path.ibnd.reserved); - - } else { - p +=3D scnprintf(p, left, "\tunknown: %llx\n", - info->params.interface_path.unknown.reserved); - } - return (p - buf); -} - -static ssize_t -edd_show_interface(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - int i; - - if (!edev || !info || !buf) { - return -EINVAL; - } - - for (i =3D 0; i < 8; i++) { - if (isprint(info->params.interface_type[i])) { - p +=3D scnprintf(p, left, "%c", info->params.interface_type[i]); - } else { - p +=3D scnprintf(p, left, " "); - } - } - if (!strncmp(info->params.interface_type, "ATAPI", 5)) { - p +=3D scnprintf(p, left, "\tdevice: %u lun: %u\n", - info->params.device_path.atapi.device, - info->params.device_path.atapi.lun); - } else if (!strncmp(info->params.interface_type, "ATA", 3)) { - p +=3D scnprintf(p, left, "\tdevice: %u\n", - info->params.device_path.ata.device); - } else if (!strncmp(info->params.interface_type, "SCSI", 4)) { - p +=3D scnprintf(p, left, "\tid: %u lun: %llu\n", - info->params.device_path.scsi.id, - info->params.device_path.scsi.lun); - } else if (!strncmp(info->params.interface_type, "USB", 3)) { - p +=3D scnprintf(p, left, "\tserial_number: %llx\n", - info->params.device_path.usb.serial_number); - } else if (!strncmp(info->params.interface_type, "1394", 4)) { - p +=3D scnprintf(p, left, "\teui: %llx\n", - info->params.device_path.i1394.eui); - } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) { - p +=3D scnprintf(p, left, "\twwid: %llx lun: %llx\n", - info->params.device_path.fibre.wwid, - info->params.device_path.fibre.lun); - } else if (!strncmp(info->params.interface_type, "I2O", 3)) { - p +=3D scnprintf(p, left, "\tidentity_tag: %llx\n", - info->params.device_path.i2o.identity_tag); - } else if (!strncmp(info->params.interface_type, "RAID", 4)) { - p +=3D scnprintf(p, left, "\tidentity_tag: %x\n", - info->params.device_path.raid.array_number); - } else if (!strncmp(info->params.interface_type, "SATA", 4)) { - p +=3D scnprintf(p, left, "\tdevice: %u\n", - info->params.device_path.sata.device); - } else { - p +=3D scnprintf(p, left, "\tunknown: %llx %llx\n", - info->params.device_path.unknown.reserved1, - info->params.device_path.unknown.reserved2); - } - - return (p - buf); -} - -/** - * edd_show_raw_data() - copies raw data to buffer for userspace to parse - * - * Returns: number of bytes written, or -EINVAL on failure - */ -static ssize_t -edd_show_raw_data(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - ssize_t len =3D sizeof (info->params); - if (!edev || !info || !buf) { - return -EINVAL; - } - - if (!(info->params.key =3D=3D 0xBEDD || info->params.key =3D=3D 0xDDBE)) - len =3D info->params.length; - - /* In case of buggy BIOSs */ - if (len > (sizeof(info->params))) - len =3D sizeof(info->params); - - memcpy(buf, &info->params, len); - return len; -} - -static ssize_t -edd_show_version(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D scnprintf(p, left, "0x%02x\n", info->version); - return (p - buf); -} - -static ssize_t -edd_show_disk80_sig(struct edd_device *edev, char *buf) -{ - char *p =3D buf; - p +=3D scnprintf(p, left, "0x%08x\n", edd_disk80_sig); - return (p - buf); -} - -static ssize_t -edd_show_extensions(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) { - p +=3D scnprintf(p, left, "Fixed disk access\n"); - } - if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) { - p +=3D scnprintf(p, left, "Device locking and ejecting\n"); - } - if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) { - p +=3D scnprintf(p, left, "Enhanced Disk Drive support\n"); - } - if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) { - p +=3D scnprintf(p, left, "64-bit extensions\n"); - } - return (p - buf); -} - -static ssize_t -edd_show_info_flags(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT) - p +=3D scnprintf(p, left, "DMA boundary error transparent\n"); - if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID) - p +=3D scnprintf(p, left, "geometry valid\n"); - if (info->params.info_flags & EDD_INFO_REMOVABLE) - p +=3D scnprintf(p, left, "removable\n"); - if (info->params.info_flags & EDD_INFO_WRITE_VERIFY) - p +=3D scnprintf(p, left, "write verify\n"); - if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION) - p +=3D scnprintf(p, left, "media change notification\n"); - if (info->params.info_flags & EDD_INFO_LOCKABLE) - p +=3D scnprintf(p, left, "lockable\n"); - if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT) - p +=3D scnprintf(p, left, "no media present\n"); - if (info->params.info_flags & EDD_INFO_USE_INT13_FN50) - p +=3D scnprintf(p, left, "use int13 fn50\n"); - return (p - buf); -} - -static ssize_t -edd_show_legacy_cylinders(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D snprintf(p, left, "0x%x\n", info->legacy_cylinders); - return (p - buf); -} - -static ssize_t -edd_show_legacy_heads(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D snprintf(p, left, "0x%x\n", info->legacy_heads); - return (p - buf); -} - -static ssize_t -edd_show_legacy_sectors(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D snprintf(p, left, "0x%x\n", info->legacy_sectors); - return (p - buf); -} - -static ssize_t -edd_show_default_cylinders(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders); - return (p - buf); -} - -static ssize_t -edd_show_default_heads(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D scnprintf(p, left, "0x%x\n", info->params.num_default_heads); - return (p - buf); -} - -static ssize_t -edd_show_default_sectors_per_track(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D scnprintf(p, left, "0x%x\n", info->params.sectors_per_track); - return (p - buf); -} - -static ssize_t -edd_show_sectors(struct edd_device *edev, char *buf) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - char *p =3D buf; - if (!edev || !info || !buf) { - return -EINVAL; - } - - p +=3D scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors); - return (p - buf); -} - - -/* - * Some device instances may not have all the above attributes, - * or the attribute values may be meaningless (i.e. if - * the device is < EDD 3.0, it won't have host_bus and interface - * information), so don't bother making files for them. Likewise - * if the default_{cylinders,heads,sectors_per_track} values - * are zero, the BIOS doesn't provide sane values, don't bother - * creating files for them either. - */ - -static int -edd_has_legacy_cylinders(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->legacy_cylinders > 0; -} - -static int -edd_has_legacy_heads(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->legacy_heads > 0; -} - -static int -edd_has_legacy_sectors(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->legacy_sectors > 0; -} - -static int -edd_has_default_cylinders(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->params.num_default_cylinders > 0; -} - -static int -edd_has_default_heads(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->params.num_default_heads > 0; -} - -static int -edd_has_default_sectors_per_track(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return -EINVAL; - return info->params.sectors_per_track > 0; -} - -static int -edd_has_edd30(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - int i, nonzero_path =3D 0; - char c; - - if (!edev || !info) - return 0; - - if (!(info->params.key =3D=3D 0xBEDD || info->params.key =3D=3D 0xDDBE)) { - return 0; - } - - for (i =3D 30; i <=3D 73; i++) { - c =3D *(((uint8_t *) info) + i + 4); - if (c) { - nonzero_path++; - break; - } - } - if (!nonzero_path) { - return 0; - } - - return 1; -} - -static int -edd_has_disk80_sig(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - if (!edev || !info) - return 0; - return info->device =3D=3D 0x80; -} - -static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, NULL); -static EDD_DEVICE_ATTR(version, 0444, edd_show_version, NULL); -static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL); -static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL); -static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL); -static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders, - edd_has_legacy_cylinders); -static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads, - edd_has_legacy_heads); -static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors, - edd_has_legacy_sectors); -static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders, - edd_has_default_cylinders); -static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads, - edd_has_default_heads); -static EDD_DEVICE_ATTR(default_sectors_per_track, 0444, - edd_show_default_sectors_per_track, - edd_has_default_sectors_per_track); -static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30); -static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30); -static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_disk80_sig, edd_has_d= isk80_sig); - - -/* These are default attributes that are added for every edd - * device discovered. - */ -static struct attribute * def_attrs[] =3D { - &edd_attr_raw_data.attr, - &edd_attr_version.attr, - &edd_attr_extensions.attr, - &edd_attr_info_flags.attr, - &edd_attr_sectors.attr, - NULL, -}; - -/* These attributes are conditional and only added for some devices. */ -static struct edd_attribute * edd_attrs[] =3D { - &edd_attr_legacy_cylinders, - &edd_attr_legacy_heads, - &edd_attr_legacy_sectors, - &edd_attr_default_cylinders, - &edd_attr_default_heads, - &edd_attr_default_sectors_per_track, - &edd_attr_interface, - &edd_attr_host_bus, - &edd_attr_mbr_signature, - NULL, -}; - -/** - * edd_release - free edd structure - * @kobj: kobject of edd structure - * - * This is called when the refcount of the edd structure - * reaches 0. This should happen right after we unregister, - * but just in case, we use the release callback anyway. - */ - -static void edd_release(struct kobject * kobj) -{ - struct edd_device * dev =3D to_edd_device(kobj); - kfree(dev); -} - -static struct kobj_type ktype_edd =3D { - .release =3D edd_release, - .sysfs_ops =3D &edd_attr_ops, - .default_attrs =3D def_attrs, -}; - -static decl_subsys(edd,&ktype_edd,NULL); - - -/** - * edd_dev_is_type() - is this EDD device a 'type' device? - * @edev - * @type - a host bus or interface identifier string per the EDD spec - * - * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise. - */ -static int -edd_dev_is_type(struct edd_device *edev, const char *type) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - - if (edev && type && info) { - if (!strncmp(info->params.host_bus_type, type, strlen(type)) || - !strncmp(info->params.interface_type, type, strlen(type))) - return 1; - } - return 0; -} - -/** - * edd_get_pci_dev() - finds pci_dev that matches edev - * @edev - edd_device - * - * Returns pci_dev if found, or NULL - */ -static struct pci_dev * -edd_get_pci_dev(struct edd_device *edev) -{ - struct edd_info *info =3D edd_dev_get_info(edev); - - if (edd_dev_is_type(edev, "PCI")) { - return pci_find_slot(info->params.interface_path.pci.bus, - PCI_DEVFN(info->params.interface_path.pci.slot, - info->params.interface_path.pci. - function)); - } - return NULL; -} - -static int -edd_create_symlink_to_pcidev(struct edd_device *edev) -{ - - struct pci_dev *pci_dev =3D edd_get_pci_dev(edev); - if (!pci_dev) - return 1; - return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev"); -} - -/* - * FIXME - as of 15-Jan-2003, there are some non-"scsi_device"s on the - * scsi_bus list. The following functions could possibly mis-access - * memory in that case. This is actually a problem with the SCSI - * layer, which is being addressed there. Until then, don't use the - * SCSI functions. - */ - -#undef CONFIG_SCSI -#undef CONFIG_SCSI_MODULE -#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE) - -struct edd_match_data { - struct edd_device * edev; - struct scsi_device * sd; -}; - -/** - * edd_match_scsidev() - * @edev - EDD device is a known SCSI device - * @sd - scsi_device with host who's parent is a PCI controller - *=20 - * returns 1 if a match is found, 0 if not. - */ -static int edd_match_scsidev(struct device * dev, void * d) -{ - struct edd_match_data * data =3D (struct edd_match_data *)d; - struct edd_info *info =3D edd_dev_get_info(data->edev); - struct scsi_device * sd =3D to_scsi_device(dev); - - if (info) { - if ((sd->channel =3D=3D info->params.interface_path.pci.channel) && - (sd->id =3D=3D info->params.device_path.scsi.id) && - (sd->lun =3D=3D info->params.device_path.scsi.lun)) { - data->sd =3D sd; - return 1; - } - } - return 0; -} - -/** - * edd_find_matching_device() - * @edev - edd_device to match - * - * Search the SCSI devices for a drive that matches the EDD=20 - * device descriptor we have. If we find a match, return it, - * otherwise, return NULL. - */ - -static struct scsi_device * -edd_find_matching_scsi_device(struct edd_device *edev) -{ - struct edd_match_data data; - struct bus_type * scsi_bus =3D find_bus("scsi"); - - if (!scsi_bus) { - return NULL; - } - - data.edev =3D edev; - - if (edd_dev_is_type(edev, "SCSI")) { - if (bus_for_each_dev(scsi_bus,NULL,&data,edd_match_scsidev)) - return data.sd; - } - return NULL; -} - -static int -edd_create_symlink_to_scsidev(struct edd_device *edev) -{ - struct pci_dev *pci_dev; - int rc =3D -EINVAL; - - pci_dev =3D edd_get_pci_dev(edev); - if (pci_dev) { - struct scsi_device * sdev =3D edd_find_matching_scsi_device(edev); - if (sdev && get_device(&sdev->sdev_driverfs_dev)) { - rc =3D sysfs_create_link(&edev->kobj, - &sdev->sdev_driverfs_dev.kobj, - "disc"); - put_device(&sdev->sdev_driverfs_dev); - } - } - return rc; -} - -#else -static int -edd_create_symlink_to_scsidev(struct edd_device *edev) -{ - return -ENOSYS; -} -#endif - - -static inline void -edd_device_unregister(struct edd_device *edev) -{ - kobject_unregister(&edev->kobj); -} - -static void edd_populate_dir(struct edd_device * edev) -{ - struct edd_attribute * attr; - int error =3D 0; - int i; - - for (i =3D 0; (attr =3D edd_attrs[i]) && !error; i++) { - if (!attr->test || - (attr->test && attr->test(edev))) - error =3D sysfs_create_file(&edev->kobj,&attr->attr); - } - - if (!error) { - edd_create_symlink_to_pcidev(edev); - edd_create_symlink_to_scsidev(edev); - } -} - -static int -edd_device_register(struct edd_device *edev, int i) -{ - int error; - - if (!edev) - return 1; - memset(edev, 0, sizeof (*edev)); - edd_dev_set_info(edev, &edd[i]); - snprintf(edev->kobj.name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x", - edd[i].device); - kobj_set_kset_s(edev,edd_subsys); - error =3D kobject_register(&edev->kobj); - if (!error) - edd_populate_dir(edev); - return error; -} - -/** - * edd_init() - creates sysfs tree of EDD data - * - * This assumes that eddnr and edd were - * assigned in setup.c already. - */ -static int __init -edd_init(void) -{ - unsigned int i; - int rc=3D0; - struct edd_device *edev; - - printk(KERN_INFO "BIOS EDD facility v%s, %d devices found\n", - EDD_VERSION, eddnr); - printk(KERN_INFO "Please report your BIOS at %s\n", REPORT_URL); - - if (!eddnr) { - printk(KERN_INFO "EDD information not available.\n"); - return 1; - } - - rc =3D firmware_register(&edd_subsys); - if (rc) - return rc; - - for (i =3D 0; i < eddnr && i < EDDMAXNR && !rc; i++) { - edev =3D kmalloc(sizeof (*edev), GFP_KERNEL); - if (!edev) - return -ENOMEM; - - rc =3D edd_device_register(edev, i); - if (rc) { - kfree(edev); - break; - } - edd_devices[i] =3D edev; - } - - if (rc) - firmware_unregister(&edd_subsys); - return rc; -} - -static void __exit -edd_exit(void) -{ - int i; - struct edd_device *edev; - - for (i =3D 0; i < eddnr && i < EDDMAXNR; i++) { - if ((edev =3D edd_devices[i])) - edd_device_unregister(edev); - } - firmware_unregister(&edd_subsys); -} - -late_initcall(edd_init); -module_exit(edd_exit); diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Tue Mar 16 10:03:36 2004 +++ b/arch/i386/kernel/setup.c Tue Mar 16 10:03:36 2004 @@ -38,10 +38,10 @@ #include #include #include +#include #include