X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Ffirmware%2Fedd.c;h=5c261e1f92b271e17094b05242c93959503dbad4;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=ac2246dd764684bb2ef638a8d4dfb9738958ea62;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index ac2246dd7..5c261e1f9 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -1,8 +1,8 @@ /* - * linux/arch/i386/kernel/edd.c + * linux/drivers/firmware/edd.c * Copyright (C) 2002, 2003, 2004 Dell Inc. * by Matt Domsch - * disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya + * disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya * legacy CHS by Patrick J. LoPresti * * BIOS Enhanced Disk Drive Services (EDD) @@ -15,9 +15,8 @@ * 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 + * Please see http://linux.dell.com/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 @@ -30,15 +29,6 @@ * */ -/* - * 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 @@ -50,24 +40,22 @@ #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> + +#define EDD_VERSION "0.16" +#define EDD_DATE "2004-Jun-25" 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" +MODULE_VERSION(EDD_VERSION); #define left (PAGE_SIZE - (p - buf) - 1) struct edd_device { + unsigned int index; + unsigned int mbr_signature; struct edd_info *info; struct kobject kobj; }; @@ -82,7 +70,7 @@ struct edd_attribute { 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]; +static struct edd_device *edd_devices[EDD_MBR_SIG_MAX]; #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \ struct edd_attribute edd_attr_##_name = { \ @@ -91,6 +79,18 @@ struct edd_attribute edd_attr_##_name = { \ .test = _test, \ }; +static int +edd_has_mbr_signature(struct edd_device *edev) +{ + return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX); +} + +static int +edd_has_edd_info(struct edd_device *edev) +{ + return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR); +} + static inline struct edd_info * edd_dev_get_info(struct edd_device *edev) { @@ -98,9 +98,13 @@ edd_dev_get_info(struct edd_device *edev) } static inline void -edd_dev_set_info(struct edd_device *edev, struct edd_info *info) +edd_dev_set_info(struct edd_device *edev, int i) { - edev->info = info; + edev->index = i; + if (edd_has_mbr_signature(edev)) + edev->mbr_signature = edd.mbr_signature[i]; + if (edd_has_edd_info(edev)) + edev->info = &edd.edd_info[i]; } #define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr) @@ -111,7 +115,7 @@ edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) { struct edd_device *dev = to_edd_device(kobj); struct edd_attribute *edd_attr = to_edd_attr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (edd_attr->show) ret = edd_attr->show(dev, buf); @@ -270,10 +274,10 @@ edd_show_version(struct edd_device *edev, char *buf) } static ssize_t -edd_show_disk80_sig(struct edd_device *edev, char *buf) +edd_show_mbr_signature(struct edd_device *edev, char *buf) { char *p = buf; - p += scnprintf(p, left, "0x%08x\n", edd_disk80_sig); + p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature); return (p - buf); } @@ -334,7 +338,7 @@ edd_show_info_flags(struct edd_device *edev, char *buf) } static ssize_t -edd_show_legacy_cylinders(struct edd_device *edev, char *buf) +edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -344,12 +348,12 @@ edd_show_legacy_cylinders(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "0x%x\n", info->legacy_cylinders); + p += snprintf(p, left, "%u\n", info->legacy_max_cylinder); return (p - buf); } static ssize_t -edd_show_legacy_heads(struct edd_device *edev, char *buf) +edd_show_legacy_max_head(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -359,12 +363,12 @@ edd_show_legacy_heads(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "0x%x\n", info->legacy_heads); + p += snprintf(p, left, "%u\n", info->legacy_max_head); return (p - buf); } static ssize_t -edd_show_legacy_sectors(struct edd_device *edev, char *buf) +edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -374,7 +378,7 @@ edd_show_legacy_sectors(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "0x%x\n", info->legacy_sectors); + p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track); return (p - buf); } @@ -389,7 +393,7 @@ edd_show_default_cylinders(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders); + p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders); return (p - buf); } @@ -404,7 +408,7 @@ edd_show_default_heads(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "0x%x\n", info->params.num_default_heads); + p += scnprintf(p, left, "%u\n", info->params.num_default_heads); return (p - buf); } @@ -419,7 +423,7 @@ edd_show_default_sectors_per_track(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track); + p += scnprintf(p, left, "%u\n", info->params.sectors_per_track); return (p - buf); } @@ -434,7 +438,7 @@ edd_show_sectors(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors); + p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors); return (p - buf); } @@ -450,39 +454,39 @@ edd_show_sectors(struct edd_device *edev, char *buf) */ static int -edd_has_legacy_cylinders(struct edd_device *edev) +edd_has_legacy_max_cylinder(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; - return info->legacy_cylinders > 0; + return 0; + return info->legacy_max_cylinder > 0; } static int -edd_has_legacy_heads(struct edd_device *edev) +edd_has_legacy_max_head(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; - return info->legacy_heads > 0; + return 0; + return info->legacy_max_head > 0; } static int -edd_has_legacy_sectors(struct edd_device *edev) +edd_has_legacy_sectors_per_track(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; - return info->legacy_sectors > 0; + return 0; + return info->legacy_sectors_per_track > 0; } static int @@ -490,10 +494,10 @@ edd_has_default_cylinders(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; + return 0; return info->params.num_default_cylinders > 0; } @@ -502,10 +506,10 @@ edd_has_default_heads(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; + return 0; return info->params.num_default_heads > 0; } @@ -514,10 +518,10 @@ edd_has_default_sectors_per_track(struct edd_device *edev) { struct edd_info *info; if (!edev) - return -EINVAL; + return 0; info = edd_dev_get_info(edev); if (!info) - return -EINVAL; + return 0; return info->params.sectors_per_track > 0; } @@ -552,29 +556,20 @@ edd_has_edd30(struct edd_device *edev) return 1; } -static int -edd_has_disk80_sig(struct edd_device *edev) -{ - struct edd_info *info; - if (!edev) - return 0; - info = edd_dev_get_info(edev); - if (!info) - return 0; - return info->device == 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(raw_data, 0444, edd_show_raw_data, edd_has_edd_info); +static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info); +static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info); +static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info); +static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info); +static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444, + edd_show_legacy_max_cylinder, + edd_has_legacy_max_cylinder); +static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head, + edd_has_legacy_max_head); +static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444, + edd_show_legacy_sectors_per_track, + edd_has_legacy_sectors_per_track); 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, @@ -584,26 +579,26 @@ static EDD_DEVICE_ATTR(default_sectors_per_track, 0444, 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_disk80_sig); +static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature); /* These are default attributes that are added for every edd - * device discovered. + * device discovered. There are none. */ static struct attribute * def_attrs[] = { - &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[] = { - &edd_attr_legacy_cylinders, - &edd_attr_legacy_heads, - &edd_attr_legacy_sectors, + &edd_attr_raw_data, + &edd_attr_version, + &edd_attr_extensions, + &edd_attr_info_flags, + &edd_attr_sectors, + &edd_attr_legacy_max_cylinder, + &edd_attr_legacy_max_head, + &edd_attr_legacy_sectors_per_track, &edd_attr_default_cylinders, &edd_attr_default_heads, &edd_attr_default_sectors_per_track, @@ -690,103 +685,6 @@ edd_create_symlink_to_pcidev(struct edd_device *edev) 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 - * - * 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 = (struct edd_match_data *)d; - struct edd_info *info = edd_dev_get_info(data->edev); - struct scsi_device * sd = to_scsi_device(dev); - - if (info) { - if ((sd->channel == info->params.interface_path.pci.channel) && - (sd->id == info->params.device_path.scsi.id) && - (sd->lun == info->params.device_path.scsi.lun)) { - data->sd = 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 - * 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 = find_bus("scsi"); - - if (!scsi_bus) { - return NULL; - } - - data.edev = 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 = -EINVAL; - - pci_dev = edd_get_pci_dev(edev); - if (pci_dev) { - struct scsi_device * sdev = edd_find_matching_scsi_device(edev); - if (sdev && get_device(&sdev->sdev_driverfs_dev)) { - rc = 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) { @@ -807,7 +705,6 @@ static void edd_populate_dir(struct edd_device * edev) if (!error) { edd_create_symlink_to_pcidev(edev); - edd_create_symlink_to_scsidev(edev); } } @@ -818,10 +715,9 @@ edd_device_register(struct edd_device *edev, int i) 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); + edd_dev_set_info(edev, i); + kobject_set_name(&edev->kobj, "int13_dev%02x", + 0x80 + i); kobj_set_kset_s(edev,edd_subsys); error = kobject_register(&edev->kobj); if (!error) @@ -829,11 +725,15 @@ edd_device_register(struct edd_device *edev, int i) return error; } +static inline int edd_num_devices(void) +{ + return max_t(unsigned char, + min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr), + min_t(unsigned char, EDDMAXNR, edd.edd_info_nr)); +} + /** * 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) @@ -842,11 +742,10 @@ edd_init(void) int rc=0; 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); + printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n", + EDD_VERSION, EDD_DATE, edd_num_devices()); - if (!eddnr) { + if (!edd_num_devices()) { printk(KERN_INFO "EDD information not available.\n"); return 1; } @@ -855,8 +754,8 @@ edd_init(void) if (rc) return rc; - for (i = 0; i < eddnr && i < EDDMAXNR && !rc; i++) { - edev = kmalloc(sizeof (*edev), GFP_KERNEL); + for (i = 0; i < edd_num_devices() && !rc; i++) { + edev = kzalloc(sizeof (*edev), GFP_KERNEL); if (!edev) return -ENOMEM; @@ -879,7 +778,7 @@ edd_exit(void) int i; struct edd_device *edev; - for (i = 0; i < eddnr && i < EDDMAXNR; i++) { + for (i = 0; i < edd_num_devices(); i++) { if ((edev = edd_devices[i])) edd_device_unregister(edev); }