text: /* ----------------------------------------------------------------------- *
   *
   *   Copyright 2009 Pierre-Alexandre Meyer
   *
   *   Some parts borrowed from chain.c32:
   *
   *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
   *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
   *
   *   Some parts borrowed from Linux:
   *
   *   Copyright (C) 2002, 2003, 2004 Dell Inc.
   *   by Matt Domsch <Matt_Domsch@dell.com>
   *
   *   This file is part of Syslinux, and is made available under
   *   the terms of the GNU General Public License version 2.
   *
   * ----------------------------------------------------------------------- */
  
  #ifndef _GEOM_H_
  #define _GEOM_H_
  
  #include <stdint.h>
  
  /**
   * INT 13 Extensions
   *
   * Note: if the size is less than 30 on call, the final DWORD will not be
   *       returned by a v2.x implementation; similarly for the Device Path info
   **/
  struct edd_device_parameters {
      uint16_t len;		/* size of returned data */
  	/**
  	 * Bitfields for IBM/MS INT 13 Extensions information flags:
  	 * Bit(s)    Description    (Table 00274)
  	 * 0    DMA boundary errors handled transparently
  	 * 1    cylinder/head/sectors-per-track information is valid
  	 * 2    removable drive
  	 * 3    write with verify supported
  	 * 4    drive has change-line support (required if drive >= 80h is removable)
  	 * 5    drive can be locked (required if drive >= 80h is removable)
  	 * 6    CHS information set to maximum supported values, not current media
  	 * 15-7    reserved (0)
  	 **/
      uint16_t info;		/* information flags */
      uint32_t cylinders;		/* number of physical cylinders on drive */
      uint32_t heads;		/* number of physical heads on drive */
      uint32_t sectors_per_track;	/* number of physical sectors per track */
      uint64_t sectors;		/* total number of sectors on drive */
      uint16_t bytes_per_sector;	/* bytes per sector */
      /* --- v2.0+ --- */
      uint32_t dpte_pointer;	/* EDD configuration parameters, FFFFh:FFFFh if not available */
      /* --- v3.0 --- */
      uint16_t device_path_information;	/* signature BEDDh to indicate presence of Device Path info */
      uint8_t device_path_length;	/* length of Device Path information, including signature and this byte (24h for v3.0) */
      uint8_t device_path_reserved;	/* reserved (0) */
      uint16_t device_path_reserved_2;	/* reserved (0) */
      uint8_t host_bus_type[4];	/* ASCIZ name of host bus ("ISA" or "PCI") */
      uint8_t interface_type[8];	/* ASCIZ name of interface type
  				 *         "ATA"
  				 *         "ATAPI"
  				 *         "SCSI"
  				 *         "USB"
  				 *         "1394" IEEE 1394 (FireWire)
  				 *         "FIBRE" Fibre Channel
  				 */
  	/**
  	 * Format of EDD v3.0 Interface Path:
  	 * Offset    Size    Description    (Table 00275)
  	 * ---ISA---
  	 * 00h    WORD    16-bit base address
  	 * 02h 6 BYTEs    reserved (0)
  	 * ---PCI---
  	 * 00h    BYTE    PCI bus number
  	 * 01h    BYTE    PCI device number
  	 * 02h    BYTE    PCI function number
  	 * 03h 5 BYTEs    reserved (0)
  	 **/
      union {
  	struct {
  	    uint16_t base_address;
  	    uint16_t reserved1;
  	    uint32_t reserved2;
  	} __attribute__ ((packed)) isa;
  	struct {
  	    uint8_t bus;
  	    uint8_t slot;
  	    uint8_t function;
  	    uint8_t channel;
  	    uint32_t reserved;
  	} __attribute__ ((packed)) pci;
  	/* pcix is same as pci */
  	struct {
  	    uint64_t reserved;
  	} __attribute__ ((packed)) ibnd;
  	struct {
  	    uint64_t reserved;
  	} __attribute__ ((packed)) xprs;
  	struct {
  	    uint64_t reserved;
  	} __attribute__ ((packed)) htpt;
  	struct {
  	    uint64_t reserved;
  	} __attribute__ ((packed)) unknown;
      } interface_path;
  	/**
  	 * Format of EDD v3.0 Device Path:
  	 * Offset    Size    Description    (Table 00276)
  	 * ---ATA---
  	 * 00h    BYTE    flag: 00h = master, 01h = slave
  	 * 01h 7 BYTEs    reserved (0)
  	 * ---ATAPI---
  	 * 00h    BYTE    flag: 00h = master, 01h = slave
  	 * 01h    BYTE    logical unit number
  	 * 02h 6 BYTEs    reserved (0)
  	 * ---SCSI---
  	 * 00h    BYTE    logical unit number
  	 * 01h 7 BYTEs    reserved (0)
  	 * ---USB---
  	 * 00h    BYTE    to be determined
  	 * 01h 7 BYTEs    reserved (0)
  	 * ---IEEE1394---
  	 * 00h    QWORD    64-bit FireWire General Unique Identifier (GUID)
  	 * ---FibreChannel---
  	 * 00h    QWORD    Word Wide Number (WWN)
  	 **/
      union {
  	struct {
  	    uint8_t device;
  	    uint8_t reserved1;
  	    uint16_t reserved2;
  	    uint32_t reserved3;
  	    uint64_t reserved4;
  	} __attribute__ ((packed)) ata;
  	struct {
  	    uint8_t device;
  	    uint8_t lun;
  	    uint8_t reserved1;
  	    uint8_t reserved2;
  	    uint32_t reserved3;
  	    uint64_t reserved4;
  	} __attribute__ ((packed)) atapi;
  	struct {
  	    uint16_t id;
  	    uint64_t lun;
  	    uint16_t reserved1;
  	    uint32_t reserved2;
  	} __attribute__ ((packed)) scsi;
  	struct {
  	    uint64_t serial_number;
  	    uint64_t reserved;
  	} __attribute__ ((packed)) usb;
  	struct {
  	    uint64_t eui;
  	    uint64_t reserved;
  	} __attribute__ ((packed)) i1394;
  	struct {
  	    uint64_t wwid;
  	    uint64_t lun;
  	} __attribute__ ((packed)) fibre;
  	struct {
  	    uint64_t identity_tag;
  	    uint64_t reserved;
  	} __attribute__ ((packed)) i2o;
  	struct {
  	    uint32_t array_number;
  	    uint32_t reserved1;
  	    uint64_t reserved2;
  	} __attribute__ ((packed)) raid;
  	struct {
  	    uint8_t device;
  	    uint8_t reserved1;
  	    uint16_t reserved2;
  	    uint32_t reserved3;
  	    uint64_t reserved4;
  	} __attribute__ ((packed)) sata;
  	struct {
  	    uint64_t reserved1;
  	    uint64_t reserved2;
  	} __attribute__ ((packed)) unknown;
      } device_path;
      uint8_t reserved;		/* reserved (0) */
      uint8_t checksum;		/* checksum of bytes 1Eh-40h (two's complement of sum, which makes
  				 * the 8-bit sum of bytes 1Eh-41h equal 00h) */
  } __attribute__ ((packed));
  
  /*
   * Disk parameters
   */
  struct driveinfo {
      int disk;			/* Disk port (0x80 - 0xff) */
      /* Legacy C/H/S */
      int cbios;			/* CHS geometry is valid */
      int legacy_max_head;
      int legacy_max_cylinder;
      int legacy_sectors_per_track;
      int legacy_max_drive;
      int legacy_type;		/* Drive type (AT/PS2 floppies only) */
      /* EDD support */
      int ebios;			/* EBIOS supported on this disk */
      int edd_version;		/* EBIOS major version */
      int edd_functionality_subset;
      struct edd_device_parameters edd_params;	/* EDD parameters */
  };
  
  /**
   * Format of Phoenix Enhanced Disk Drive Spec translated drive parameter table:
   * Offset    Size    Description    (Table 00277)
   * 00h    WORD    number of cylinders
   * 02h    BYTE    number of heads
   * 03h    BYTE    A0h (signature indicating translated table)
   * 04h    BYTE    number of physical sectors per track
   * 05h    WORD    starting write precompensation cylinder number
   * 07h    BYTE    reserved
   * 08h    BYTE    control byte (see #03198 at INT 41"DISK 0")
   * 09h    WORD    number of physical cylinders
   * 0Bh    BYTE    number of physical heads
   * 0Ch    WORD    cylinder number of landing zone
   * 0Eh    BYTE    number of logical sectors per track
   * 0Fh    BYTE    checksum
   * Program: the Phoenix Enhanced Disk Drive Specification is an addition to the
   *     IBM/MS INT 13 extensions
   *
   * Format of Phoenix Enhanced Disk Drive Spec Fixed Disk Parameter Table:
   * Offset    Size    Description    (Table 00278)
   * 00h    WORD    physical I/O port base address
   * 02h    WORD    disk-drive control port address
   * 04h    BYTE    drive flags (see #00279)
   * 05h    BYTE    proprietary information
   *         bits 7-4 reserved (0)
   *         bits 3-0: Phoenix proprietary (used by BIOS)
   * 06h    BYTE    IRQ for drive (bits 3-0; bits 7-4 reserved and must be 0)
   * 07h    BYTE    sector count for multi-sector transfers
   * 08h    BYTE    DMA control
   *         bits 7-4: DMA type (0-2) as per ATA-2 specification
   *         bits 3-0: DMA channel
   * 09h    BYTE    programmed I/O control
   *         bits 7-4: reserved (0)
   *         bits 3-0: PIO type (1-4) as per ATA-2 specification
   * 0Ah    WORD    drive options (see #00280)
   * 0Ch 2 BYTEs    reserved (0)
   * 0Eh    BYTE    extension revision level (high nybble=major, low nybble=minor)
   *         (currently 10h for v1.0 and 11h for v1.1-3.0)
   * 0Fh    BYTE    2's complement checksum of bytes 00h-0Eh
   *         8-bit sum of all bytes 00h-0Fh should equal 00h
   * SeeAlso: #00277
   *
   * Bitfields for Phoenix Enhanced Disk Drive Spec drive flags:
   * Bit(s)    Description    (Table 00279)
   * 7    reserved (1)
   * 6    LBA enabled
   * 5    reserved (1)
   * 4    drive is slave
   * 3-0    reserved (0)
   * SeeAlso: #00278,#00280
   *
   * Bitfields for Phoenix Enhanced Disk Drive Spec drive options:
   * Bit(s)    Description    (Table 00280)
   * 0    fast PIO enabled
   * 1    fast DMA access enabled
   * 2    block PIO (multi-sector transfers) enabled
   * 3    CHS translation enabled
   * 4    LBA translation enabled
   * 5    removable media
   * 6    ATAPI device (CD-ROM)
   * 7    32-bit transfer mode
   * ---v1.1+ ---
   * 8    ATAPI device uses DRQ to signal readiness for packet command
   *     (must be 0 if bit 6 is 0)
   * 10-9    translation type (must be 00 if bit 3 is 0)
   *     00 Phoenix bit-shifting translation
   *     01 LBA-assisted translation
   *     10 reserved
   *     11 proprietary translation
   * ---v3.0---
   * 11    Ultra DMA access enabled
   * 15-12    reserved
   **/
  
  /*
   * Values for diskette drive type:
   *     01h    360K
   *     02h    1.2M
   *     03h    720K
   *     04h    1.44M
   *     05h    ???
   *            reportedly an obscure drive type shipped on some IBM machines,
   *            2.88M on some machines (at least AMI 486 BIOS)
   *     06h    2.88M
   *     10h    ATAPI Removable Media Device
   */
  enum diskette_drive_types {
      DISKETTE_360K = 1,
      DISKETTE_1_2M = 2,
      DISKETTE_720K = 3,
      DISKETTE_1_44M = 4,
      DISKETTE_2_88M = 6,
      DISKETTE_ATAPI = 10,
  };
  
  /**
   * chs_to_lba - compute lba value from cylinder, head and sector number
   **/
  static inline int chs_to_lba(const struct driveinfo *drive_info,
  			     const unsigned int cylinder,
  			     const unsigned int head, const unsigned int sector)
  {
      /* Use EDD, if valid */
      if (drive_info->edd_params.sectors_per_track > 0 &&
  	drive_info->edd_params.heads > 0)
  	return (sector - 1) +
  	    (head * drive_info->edd_params.sectors_per_track) +
  	    (cylinder * (drive_info->edd_params.heads) *
  	     drive_info->edd_params.sectors_per_track);
      else if (drive_info->cbios)
  	return (sector - 1) + (head * drive_info->legacy_sectors_per_track) +
  	    (cylinder * (drive_info->legacy_max_head + 1) *
  	     drive_info->legacy_sectors_per_track);
  }
  
  void lba_to_chs(const struct driveinfo *drive_info, const int lba,
  		unsigned int *cylinder, unsigned int *head,
  		unsigned int *sector);
  int get_drive_parameters(struct driveinfo *drive_info);
  
  #endif /* _GEOM_H */
  