CTC++ Coverage Report - Execution Profile    #395/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: drivers/firmware/edd.c
Instrumentation mode: function-decision-multicondition
TER: 21 % ( 81/377)

Start/ End/    
True False - Line Source

  1 /*
  2  * linux/arch/i386/kernel/edd.c
  3  *  Copyright (C) 2002, 2003, 2004 Dell Inc.
  4  *  by Matt Domsch <Matt_Domsch@dell.com>
  5  *  disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
  6  *  legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
  7  *
  8  * BIOS Enhanced Disk Drive Services (EDD)
  9  * conformant to T13 Committee www.t13.org
  10  *   projects 1572D, 1484D, 1386D, 1226DT
  11  *
  12  * This code takes information provided by BIOS EDD calls
  13  * fn41 - Check Extensions Present and
  14  * fn48 - Get Device Parametes with EDD extensions
  15  * made in setup.S, copied to safe structures in setup.c,
  16  * and presents it in sysfs.
  17  *
  18  * Please see http://linux.dell.com/edd30/results.html for
  19  * the list of BIOSs which have been reported to implement EDD.
  20  *
  21  * This program is free software; you can redistribute it and/or modify
  22  * it under the terms of the GNU General Public License v2.0 as published by
  23  * the Free Software Foundation
  24  *
  25  * This program is distributed in the hope that it will be useful,
  26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  28  * GNU General Public License for more details.
  29  *
  30  */
  31 
  32 #include <linux/module.h>
  33 #include <linux/string.h>
  34 #include <linux/types.h>
  35 #include <linux/init.h>
  36 #include <linux/stat.h>
  37 #include <linux/err.h>
  38 #include <linux/ctype.h>
  39 #include <linux/slab.h>
  40 #include <linux/limits.h>
  41 #include <linux/device.h>
  42 #include <linux/pci.h>
  43 #include <linux/blkdev.h>
  44 #include <linux/edd.h>
  45 
  46 #define EDD_VERSION "0.16"
  47 #define EDD_DATE    "2004-Jun-25"
  48 
  49 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
  50 MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
  51 MODULE_LICENSE("GPL");
  52 MODULE_VERSION(EDD_VERSION);
  53 
  54 #define left (PAGE_SIZE - (p - buf) - 1)
  55 
  56 struct edd_device {
  57    unsigned int index;
  58    unsigned int mbr_signature;
  59    struct edd_info *info;
  60    struct kobject kobj;
  61 };
  62 
  63 struct edd_attribute {
  64    struct attribute attr;
  65    ssize_t(*show) (struct edd_device * edev, char *buf);
  66    int (*test) (struct edd_device * edev);
  67 };
  68 
  69 /* forward declarations */
  70 static int edd_dev_is_type(struct edd_device *edev, const char *type);
  71 static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
  72 
  73 static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
  74 
  75 #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
  76 struct edd_attribute edd_attr_##_name = {    \
  77    .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },   \
  78    .show   = _show,            \
  79    .test   = _test,            \
  80 };
  81 
  82 static int
 
12   83 edd_has_mbr_signature(struct edd_device *edev)
  84 {
12    85    return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX);
  86 }
  87 
  88 static int
 
36   89 edd_has_edd_info(struct edd_device *edev)
  90 {
36    91    return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR);
  92 }
  93 
  94 static inline struct edd_info *
 
60   95 edd_dev_get_info(struct edd_device *edev)
  96 {
60    97    return edev->info;
  98 }
  99 
  100 static inline void
 
  101 edd_dev_set_info(struct edd_device *edev, int i)
  102 {
  103    edev->index = i;
- 104    if (edd_has_mbr_signature(edev))
  105       edev->mbr_signature = edd.mbr_signature[i];
- 106    if (edd_has_edd_info(edev))
  107       edev->info = &edd.edd_info[i];
  108 }
  109 
  110 #define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
  111 #define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
  112 
  113 static ssize_t
 
- 114 edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
  115 {
  116    struct edd_device *dev = to_edd_device(kobj);
  117    struct edd_attribute *edd_attr = to_edd_attr(attr);
  118    ssize_t ret = -EIO;
  119 
- 120    if (edd_attr->show)
  121       ret = edd_attr->show(dev, buf);
 - 122    return ret;
  123 }
  124 
  125 static struct sysfs_ops edd_attr_ops = {
  126    .show = edd_attr_show,
  127 };
  128 
  129 static ssize_t
 
- 130 edd_show_host_bus(struct edd_device *edev, char *buf)
  131 {
  132    struct edd_info *info;
  133    char *p = buf;
  134    int i;
  135 
- 136    if (!edev)
 - 137       return -EINVAL;
  138    info = edd_dev_get_info(edev);
- 139    if (!info || !buf)
 - 139   T || _
 - 139   F || T
 - 139   F || F
 - 140       return -EINVAL;
  141 
- 142    for (i = 0; i < 4; i++) {
- 143       if (isprint(info->params.host_bus_type[i])) {
  144          p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
    145       } else {
  146          p += scnprintf(p, left, " ");
  147       }
  148    }
  149 
- 150    if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
  151       p += scnprintf(p, left, "\tbase_address: %x\n",
  152               info->params.interface_path.isa.base_address);
  153    } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
- 154          !strncmp(info->params.host_bus_type, "PCI", 3)) {
 - 154   T || _
 - 154   F || T
 - 154   F || F
  155       p += scnprintf(p, left,
  156               "\t%02x:%02x.%d  channel: %u\n",
  157               info->params.interface_path.pci.bus,
  158               info->params.interface_path.pci.slot,
  159               info->params.interface_path.pci.function,
  160               info->params.interface_path.pci.channel);
  161    } else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
  162          !strncmp(info->params.host_bus_type, "XPRS", 4) ||
- 163          !strncmp(info->params.host_bus_type, "HTPT", 4)) {
 - 163   T || _ || _
 - 163   F || T || _
 - 163   F || F || T
 - 163   F || F || F
  164       p += scnprintf(p, left,
  165               "\tTBD: %llx\n",
  166               info->params.interface_path.ibnd.reserved);
  167 
    168    } else {
  169       p += scnprintf(p, left, "\tunknown: %llx\n",
  170               info->params.interface_path.unknown.reserved);
  171    }
 - 172    return (p - buf);
  173 }
  174 
  175 static ssize_t
 
- 176 edd_show_interface(struct edd_device *edev, char *buf)
  177 {
  178    struct edd_info *info;
  179    char *p = buf;
  180    int i;
  181 
- 182    if (!edev)
 - 183       return -EINVAL;
  184    info = edd_dev_get_info(edev);
- 185    if (!info || !buf)
 - 185   T || _
 - 185   F || T
 - 185   F || F
 - 186       return -EINVAL;
  187 
- 188    for (i = 0; i < 8; i++) {
- 189       if (isprint(info->params.interface_type[i])) {
  190          p += scnprintf(p, left, "%c", info->params.interface_type[i]);
    191       } else {
  192          p += scnprintf(p, left, " ");
  193       }
  194    }
- 195    if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
  196       p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
  197               info->params.device_path.atapi.device,
  198               info->params.device_path.atapi.lun);
- 199    } else if (!strncmp(info->params.interface_type, "ATA", 3)) {
  200       p += scnprintf(p, left, "\tdevice: %u\n",
  201               info->params.device_path.ata.device);
- 202    } else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
  203       p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
  204               info->params.device_path.scsi.id,
  205               info->params.device_path.scsi.lun);
- 206    } else if (!strncmp(info->params.interface_type, "USB", 3)) {
  207       p += scnprintf(p, left, "\tserial_number: %llx\n",
  208               info->params.device_path.usb.serial_number);
- 209    } else if (!strncmp(info->params.interface_type, "1394", 4)) {
  210       p += scnprintf(p, left, "\teui: %llx\n",
  211               info->params.device_path.i1394.eui);
- 212    } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
  213       p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
  214               info->params.device_path.fibre.wwid,
  215               info->params.device_path.fibre.lun);
- 216    } else if (!strncmp(info->params.interface_type, "I2O", 3)) {
  217       p += scnprintf(p, left, "\tidentity_tag: %llx\n",
  218               info->params.device_path.i2o.identity_tag);
- 219    } else if (!strncmp(info->params.interface_type, "RAID", 4)) {
  220       p += scnprintf(p, left, "\tidentity_tag: %x\n",
  221               info->params.device_path.raid.array_number);
- 222    } else if (!strncmp(info->params.interface_type, "SATA", 4)) {
  223       p += scnprintf(p, left, "\tdevice: %u\n",
  224               info->params.device_path.sata.device);
    225    } else {
  226       p += scnprintf(p, left, "\tunknown: %llx %llx\n",
  227               info->params.device_path.unknown.reserved1,
  228               info->params.device_path.unknown.reserved2);
  229    }
  230 
 - 231    return (p - buf);
  232 }
  233 
  234 /**
  235  * edd_show_raw_data() - copies raw data to buffer for userspace to parse
  236  *
  237  * Returns: number of bytes written, or -EINVAL on failure
  238  */
  239 static ssize_t
 
- 240 edd_show_raw_data(struct edd_device *edev, char *buf)
  241 {
  242    struct edd_info *info;
  243    ssize_t len = sizeof (info->params);
- 244    if (!edev)
 - 245       return -EINVAL;
  246    info = edd_dev_get_info(edev);
- 247    if (!info || !buf)
 - 247   T || _
 - 247   F || T
 - 247   F || F
 - 248       return -EINVAL;
  249 
- 250    if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
 - 250   !(F || F)
 - 250   !(T || _)
 - 250   !(F || T)
  251       len = info->params.length;
  252 
  253    /* In case of buggy BIOSs */
- 254    if (len > (sizeof(info->params)))
  255       len = sizeof(info->params);
  256 
  257    memcpy(buf, &info->params, len);
 - 258    return len;
  259 }
  260 
  261 static ssize_t
 
- 262 edd_show_version(struct edd_device *edev, char *buf)
  263 {
  264    struct edd_info *info;
  265    char *p = buf;
- 266    if (!edev)
 - 267       return -EINVAL;
  268    info = edd_dev_get_info(edev);
- 269    if (!info || !buf)
 - 269   T || _
 - 269   F || T
 - 269   F || F
 - 270       return -EINVAL;
  271 
  272    p += scnprintf(p, left, "0x%02x\n", info->version);
 - 273    return (p - buf);
  274 }
  275 
  276 static ssize_t
 
- 277 edd_show_mbr_signature(struct edd_device *edev, char *buf)
  278 {
  279    char *p = buf;
  280    p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
 - 281    return (p - buf);
  282 }
  283 
  284 static ssize_t
 
- 285 edd_show_extensions(struct edd_device *edev, char *buf)
  286 {
  287    struct edd_info *info;
  288    char *p = buf;
- 289    if (!edev)
 - 290       return -EINVAL;
  291    info = edd_dev_get_info(edev);
- 292    if (!info || !buf)
 - 292   T || _
 - 292   F || T
 - 292   F || F
 - 293       return -EINVAL;
  294 
- 295    if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
  296       p += scnprintf(p, left, "Fixed disk access\n");
  297    }
- 298    if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
  299       p += scnprintf(p, left, "Device locking and ejecting\n");
  300    }
- 301    if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
  302       p += scnprintf(p, left, "Enhanced Disk Drive support\n");
  303    }
- 304    if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
  305       p += scnprintf(p, left, "64-bit extensions\n");
  306    }
 - 307    return (p - buf);
  308 }
  309 
  310 static ssize_t
 
- 311 edd_show_info_flags(struct edd_device *edev, char *buf)
  312 {
  313    struct edd_info *info;
  314    char *p = buf;
- 315    if (!edev)
 - 316       return -EINVAL;
  317    info = edd_dev_get_info(edev);
- 318    if (!info || !buf)
 - 318   T || _
 - 318   F || T
 - 318   F || F
 - 319       return -EINVAL;
  320 
- 321    if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
  322       p += scnprintf(p, left, "DMA boundary error transparent\n");
- 323    if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
  324       p += scnprintf(p, left, "geometry valid\n");
- 325    if (info->params.info_flags & EDD_INFO_REMOVABLE)
  326       p += scnprintf(p, left, "removable\n");
- 327    if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
  328       p += scnprintf(p, left, "write verify\n");
- 329    if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
  330       p += scnprintf(p, left, "media change notification\n");
- 331    if (info->params.info_flags & EDD_INFO_LOCKABLE)
  332       p += scnprintf(p, left, "lockable\n");
- 333    if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
  334       p += scnprintf(p, left, "no media present\n");
- 335    if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
  336       p += scnprintf(p, left, "use int13 fn50\n");
 - 337    return (p - buf);
  338 }
  339 
  340 static ssize_t
 
- 341 edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
  342 {
  343    struct edd_info *info;
  344    char *p = buf;
- 345    if (!edev)
 - 346       return -EINVAL;
  347    info = edd_dev_get_info(edev);
- 348    if (!info || !buf)
 - 348   T || _
 - 348   F || T
 - 348   F || F
 - 349       return -EINVAL;
  350 
  351    p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
 - 352    return (p - buf);
  353 }
  354 
  355 static ssize_t
 
- 356 edd_show_legacy_max_head(struct edd_device *edev, char *buf)
  357 {
  358    struct edd_info *info;
  359    char *p = buf;
- 360    if (!edev)
 - 361       return -EINVAL;
  362    info = edd_dev_get_info(edev);
- 363    if (!info || !buf)
 - 363   T || _
 - 363   F || T
 - 363   F || F
 - 364       return -EINVAL;
  365 
  366    p += snprintf(p, left, "%u\n", info->legacy_max_head);
 - 367    return (p - buf);
  368 }
  369 
  370 static ssize_t
 
- 371 edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
  372 {
  373    struct edd_info *info;
  374    char *p = buf;
- 375    if (!edev)
 - 376       return -EINVAL;
  377    info = edd_dev_get_info(edev);
- 378    if (!info || !buf)
 - 378   T || _
 - 378   F || T
 - 378   F || F
 - 379       return -EINVAL;
  380 
  381    p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
 - 382    return (p - buf);
  383 }
  384 
  385 static ssize_t
 
- 386 edd_show_default_cylinders(struct edd_device *edev, char *buf)
  387 {
  388    struct edd_info *info;
  389    char *p = buf;
- 390    if (!edev)
 - 391       return -EINVAL;
  392    info = edd_dev_get_info(edev);
- 393    if (!info || !buf)
 - 393   T || _
 - 393   F || T
 - 393   F || F
 - 394       return -EINVAL;
  395 
  396    p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
 - 397    return (p - buf);
  398 }
  399 
  400 static ssize_t
 
- 401 edd_show_default_heads(struct edd_device *edev, char *buf)
  402 {
  403    struct edd_info *info;
  404    char *p = buf;
- 405    if (!edev)
 - 406       return -EINVAL;
  407    info = edd_dev_get_info(edev);
- 408    if (!info || !buf)
 - 408   T || _
 - 408   F || T
 - 408   F || F
 - 409       return -EINVAL;
  410 
  411    p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
 - 412    return (p - buf);
  413 }
  414 
  415 static ssize_t
 
- 416 edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
  417 {
  418    struct edd_info *info;
  419    char *p = buf;
- 420    if (!edev)
 - 421       return -EINVAL;
  422    info = edd_dev_get_info(edev);
- 423    if (!info || !buf)
 - 423   T || _
 - 423   F || T
 - 423   F || F
 - 424       return -EINVAL;
  425 
  426    p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
 - 427    return (p - buf);
  428 }
  429 
  430 static ssize_t
 
- 431 edd_show_sectors(struct edd_device *edev, char *buf)
  432 {
  433    struct edd_info *info;
  434    char *p = buf;
- 435    if (!edev)
 - 436       return -EINVAL;
  437    info = edd_dev_get_info(edev);
- 438    if (!info || !buf)
 - 438   T || _
 - 438   F || T
 - 438   F || F
 - 439       return -EINVAL;
  440 
  441    p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
 - 442    return (p - buf);
  443 }
  444 
  445 
  446 /*
  447  * Some device instances may not have all the above attributes,
  448  * or the attribute values may be meaningless (i.e. if
  449  * the device is < EDD 3.0, it won't have host_bus and interface
  450  * information), so don't bother making files for them.  Likewise
  451  * if the default_{cylinders,heads,sectors_per_track} values
  452  * are zero, the BIOS doesn't provide sane values, don't bother
  453  * creating files for them either.
  454  */
  455 
  456 static int
 
  457 edd_has_legacy_max_cylinder(struct edd_device *edev)
  458 {
  459    struct edd_info *info;
- 460    if (!edev)
 - 461       return 0;
  462    info = edd_dev_get_info(edev);
- 463   &n