#include <stdint.h>
#include <ipxe/list.h>
+#include <ipxe/edd.h>
#include <realmode.h>
/**
#define INT13_EXTENDED_READ 0x42
/** Extended write */
#define INT13_EXTENDED_WRITE 0x43
+/** Verify sectors */
+#define INT13_EXTENDED_VERIFY 0x44
+/** Extended seek */
+#define INT13_EXTENDED_SEEK 0x47
/** Get extended drive parameters */
#define INT13_GET_EXTENDED_PARAMETERS 0x48
/** Get CD-ROM status / terminate emulation */
struct int13_disk_address {
/** Size of the packet, in bytes */
uint8_t bufsize;
- /** Reserved, must be zero */
- uint8_t reserved;
+ /** Reserved */
+ uint8_t reserved_a;
/** Block count */
- uint16_t count;
+ uint8_t count;
+ /** Reserved */
+ uint8_t reserved_b;
/** Data buffer */
struct segoff buffer;
/** Starting block number */
uint64_t lba;
- /** Data buffer (EDD-3.0 only) */
+ /** Data buffer (EDD 3.0+ only) */
uint64_t buffer_phys;
+ /** Block count (EDD 4.0+ only) */
+ uint32_t long_count;
+ /** Reserved */
+ uint32_t reserved_c;
} __attribute__ (( packed ));
/** INT 13 disk parameters */
uint64_t sectors;
/** Bytes per sector */
uint16_t sector_size;
+ /** Device parameter table extension */
+ struct segoff dpte;
+ /** Device path information */
+ struct edd_device_path_information dpi;
} __attribute__ (( packed ));
/**
#define INT13_EXTENSION_REMOVABLE 0x02
/** EDD functions supported */
#define INT13_EXTENSION_EDD 0x04
+/** 64-bit extensions are present */
+#define INT13_EXTENSION_64BIT 0x08
/** @} */
/** @} */
+/** Maximum number of sectors for which CHS geometry is allowed to be valid
+ *
+ * This number is taken from the EDD specification.
+ */
+#define INT13_MAX_CHS_SECTORS 15482880
+
/** Bootable CD-ROM specification packet */
struct int13_cdrom_specification {
/** Size of packet in bytes */
#include <ipxe/timer.h>
#include <ipxe/acpi.h>
#include <ipxe/sanboot.h>
+#include <ipxe/device.h>
+#include <ipxe/pci.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
if ( ix86->regs.bx == 0x55aa ) {
DBGC2 ( int13, "INT13 extensions installation check\n" );
ix86->regs.bx = 0xaa55;
- ix86->regs.cx = INT13_EXTENSION_LINEAR;
- return INT13_EXTENSION_VER_1_X;
+ ix86->regs.cx = ( INT13_EXTENSION_LINEAR |
+ INT13_EXTENSION_EDD |
+ INT13_EXTENSION_64BIT );
+ return INT13_EXTENSION_VER_3_0;
} else {
return -INT13_STATUS_INVALID;
}
userptr_t buffer,
size_t len ) ) {
struct int13_disk_address addr;
+ uint8_t bufsize;
uint64_t lba;
unsigned long count;
userptr_t buffer;
int rc;
+ /* Get buffer size */
+ get_real ( bufsize, ix86->segs.ds,
+ ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
+ if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) {
+ DBGC2 ( int13, "<invalid buffer size %#02x\n>\n", bufsize );
+ return -INT13_STATUS_INVALID;
+ }
+
/* Read parameters from disk address structure */
- copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr ));
+ memset ( &addr, 0, sizeof ( addr ) );
+ copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize );
lba = addr.lba;
- count = addr.count;
- buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset );
+ DBGC2 ( int13, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) );
+ if ( ( addr.count == 0xff ) ||
+ ( ( addr.buffer.segment == 0xffff ) &&
+ ( addr.buffer.offset == 0xffff ) ) ) {
+ buffer = phys_to_user ( addr.buffer_phys );
+ DBGC2 ( int13, "%08llx",
+ ( ( unsigned long long ) addr.buffer_phys ) );
+ } else {
+ buffer = real_to_user ( addr.buffer.segment,
+ addr.buffer.offset );
+ DBGC2 ( int13, "%04x:%04x", addr.buffer.segment,
+ addr.buffer.offset );
+ }
+ if ( addr.count <= 0x7f ) {
+ count = addr.count;
+ } else if ( addr.count == 0xff ) {
+ count = addr.long_count;
+ } else {
+ DBGC2 ( int13, " <invalid count %#02x>\n", addr.count );
+ return -INT13_STATUS_INVALID;
+ }
+ DBGC2 ( int13, " (count %ld)\n", count );
- DBGC2 ( int13, "LBA %08llx <-> %04x:%04x (count %ld)\n",
- ( ( unsigned long long ) lba ), addr.buffer.segment,
- addr.buffer.offset, count );
-
/* Read from / write to block device */
if ( ( rc = int13_rw ( int13, lba, count, buffer, block_rw ) ) != 0 ) {
DBGC ( int13, "INT13 drive %02x extended I/O failed: %s\n",
int13->drive, strerror ( rc ) );
+ /* Record that no blocks were transferred successfully */
+ addr.count = 0;
+ put_real ( addr.count, ix86->segs.ds,
+ ( ix86->regs.si +
+ offsetof ( typeof ( addr ), count ) ) );
return -INT13_STATUS_READ_ERROR;
}
return int13_extended_rw ( int13, ix86, block_write );
}
+/**
+ * INT 13, 44 - Verify sectors
+ *
+ * @v int13 Emulated drive
+ * @v ds:si Disk address packet
+ * @ret status Status code
+ */
+static int int13_extended_verify ( struct int13_drive *int13,
+ struct i386_all_regs *ix86 ) {
+ struct int13_disk_address addr;
+ uint64_t lba;
+ unsigned long count;
+
+ /* Read parameters from disk address structure */
+ if ( DBG_EXTRA ) {
+ copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
+ sizeof ( addr ));
+ lba = addr.lba;
+ count = addr.count;
+ DBGC2 ( int13, "Verify: LBA %08llx (count %ld)\n",
+ ( ( unsigned long long ) lba ), count );
+ }
+
+ /* We have no mechanism for verifying sectors */
+ return -INT13_STATUS_INVALID;
+}
+
+/**
+ * INT 13, 44 - Extended seek
+ *
+ * @v int13 Emulated drive
+ * @v ds:si Disk address packet
+ * @ret status Status code
+ */
+int int13_extended_seek ( struct int13_drive *int13,
+ struct i386_all_regs *ix86 ) {
+ struct int13_disk_address addr;
+ uint64_t lba;
+ unsigned long count;
+
+ /* Read parameters from disk address structure */
+ if ( DBG_EXTRA ) {
+ copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
+ sizeof ( addr ));
+ lba = addr.lba;
+ count = addr.count;
+ DBGC2 ( int13, "Seek: LBA %08llx (count %ld)\n",
+ ( ( unsigned long long ) lba ), count );
+ }
+
+ /* Ignore and return success */
+ return 0;
+}
+
+/**
+ * Build device path information
+ *
+ * @v int13 Emulated drive
+ * @v dpi Device path information
+ * @ret rc Return status code
+ */
+static int int13_device_path_info ( struct int13_drive *int13,
+ struct edd_device_path_information *dpi ) {
+ struct device *device;
+ struct device_description *desc;
+ unsigned int i;
+ uint8_t sum = 0;
+ int rc;
+
+ /* Get underlying hardware device */
+ device = identify_device ( &int13->block );
+ if ( ! device ) {
+ DBGC ( int13, "INT13 drive %02x cannot identify hardware "
+ "device\n", int13->drive );
+ return -ENODEV;
+ }
+
+ /* Fill in bus type and interface path */
+ desc = &device->desc;
+ switch ( desc->bus_type ) {
+ case BUS_TYPE_PCI:
+ dpi->host_bus_type.type = EDD_BUS_TYPE_PCI;
+ dpi->interface_path.pci.bus = PCI_BUS ( desc->location );
+ dpi->interface_path.pci.slot = PCI_SLOT ( desc->location );
+ dpi->interface_path.pci.function = PCI_FUNC ( desc->location );
+ dpi->interface_path.pci.channel = 0xff; /* unused */
+ break;
+ default:
+ DBGC ( int13, "INT13 drive %02x unrecognised bus type %d\n",
+ int13->drive, desc->bus_type );
+ return -ENOTSUP;
+ }
+
+ /* Get EDD block device description */
+ if ( ( rc = edd_describe ( &int13->block, &dpi->interface_type,
+ &dpi->device_path ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x cannot identify block device: "
+ "%s\n", int13->drive, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Fill in common fields and fix checksum */
+ dpi->key = EDD_DEVICE_PATH_INFO_KEY;
+ dpi->len = sizeof ( *dpi );
+ for ( i = 0 ; i < sizeof ( *dpi ) ; i++ )
+ sum += *( ( ( uint8_t * ) dpi ) + i );
+ dpi->checksum -= sum;
+
+ return 0;
+}
+
/**
* INT 13, 48 - Get extended parameters
*
*/
static int int13_get_extended_parameters ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- struct int13_disk_parameters params = {
- .bufsize = sizeof ( params ),
- .flags = INT13_FL_DMA_TRANSPARENT,
- .cylinders = int13->cylinders,
- .heads = int13->heads,
- .sectors_per_track = int13->sectors_per_track,
- .sectors = int13->capacity.blocks,
- .sector_size = int13->capacity.blksize,
- };
-
- DBGC2 ( int13, "Get extended drive parameters to %04x:%04x\n",
- ix86->segs.ds, ix86->regs.si );
+ struct int13_disk_parameters params;
+ struct segoff address;
+ size_t len = sizeof ( params );
+ uint16_t bufsize;
+ int rc;
+
+ /* Get buffer size */
+ get_real ( bufsize, ix86->segs.ds,
+ ( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));
+
+ DBGC2 ( int13, "Get extended drive parameters to %04x:%04x+%02x\n",
+ ix86->segs.ds, ix86->regs.si, bufsize );
+
+ /* Build drive parameters */
+ memset ( ¶ms, 0, sizeof ( params ) );
+ params.flags = INT13_FL_DMA_TRANSPARENT;
+ if ( ( int13->cylinders < 1024 ) &&
+ ( int13->capacity.blocks <= INT13_MAX_CHS_SECTORS ) ) {
+ params.flags |= INT13_FL_CHS_VALID;
+ }
+ params.cylinders = int13->cylinders;
+ params.heads = int13->heads;
+ params.sectors_per_track = int13->sectors_per_track;
+ params.sectors = int13->capacity.blocks;
+ params.sector_size = int13->capacity.blksize;
+ memset ( ¶ms.dpte, 0xff, sizeof ( params.dpte ) );
+ if ( ( rc = int13_device_path_info ( int13, ¶ms.dpi ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x could not provide device "
+ "path information: %s\n",
+ int13->drive, strerror ( rc ) );
+ len = offsetof ( typeof ( params ), dpi );
+ }
+
+ /* Calculate returned "buffer size" (which will be less than
+ * the length actually copied if device path information is
+ * present).
+ */
+ if ( bufsize < offsetof ( typeof ( params ), dpte ) )
+ return -INT13_STATUS_INVALID;
+ if ( bufsize < offsetof ( typeof ( params ), dpi ) ) {
+ params.bufsize = offsetof ( typeof ( params ), dpte );
+ } else {
+ params.bufsize = offsetof ( typeof ( params ), dpi );
+ }
+
+ DBGC ( int13, "INT 13 drive %02x described using extended "
+ "parameters:\n", int13->drive );
+ address.segment = ix86->segs.ds;
+ address.offset = ix86->regs.si;
+ DBGC_HDA ( int13, address, ¶ms, len );
+
+ /* Return drive parameters */
+ if ( len > bufsize )
+ len = bufsize;
+ copy_to_real ( ix86->segs.ds, ix86->regs.si, ¶ms, len );
- copy_to_real ( ix86->segs.ds, ix86->regs.si, ¶ms,
- sizeof ( params ) );
return 0;
}
case INT13_EXTENDED_WRITE:
status = int13_extended_write ( int13, ix86 );
break;
+ case INT13_EXTENDED_VERIFY:
+ status = int13_extended_verify ( int13, ix86 );
+ break;
+ case INT13_EXTENDED_SEEK:
+ status = int13_extended_seek ( int13, ix86 );
+ break;
case INT13_GET_EXTENDED_PARAMETERS:
status = int13_get_extended_parameters ( int13, ix86 );
break;
#include <string.h>
#include <ipxe/list.h>
#include <ipxe/tables.h>
-#include <ipxe/device.h>
#include <ipxe/init.h>
+#include <ipxe/interface.h>
+#include <ipxe/device.h>
/**
* @file
.startup = probe_devices,
.shutdown = remove_devices,
};
+
+/**
+ * Identify a device behind an interface
+ *
+ * @v intf Interface
+ * @ret device Device, or NULL
+ */
+struct device * identify_device ( struct interface *intf ) {
+ struct interface *dest;
+ identify_device_TYPE ( void * ) *op =
+ intf_get_dest_op ( intf, identify_device, &dest );
+ void *object = intf_object ( dest );
+ void *device;
+
+ if ( op ) {
+ device = op ( object );
+ } else {
+ /* Default is to return NULL */
+ device = NULL;
+ }
+
+ intf_put ( dest );
+ return device;
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/interface.h>
+#include <ipxe/edd.h>
+
+/** @file
+ *
+ * Enhanced Disk Drive specification
+ *
+ */
+
+/**
+ * Describe a disk device using EDD
+ *
+ * @v intf Interface
+ * @v type EDD interface type
+ * @v path EDD device path
+ * @ret rc Return status code
+ */
+int edd_describe ( struct interface *intf, struct edd_interface_type *type,
+ union edd_device_path *path ) {
+ struct interface *dest;
+ edd_describe_TYPE ( void * ) *op =
+ intf_get_dest_op ( intf, edd_describe, &dest );
+ void *object = intf_object ( dest );
+ int rc;
+
+ if ( op ) {
+ rc = op ( object, type, path );
+ } else {
+ /* Default is to not support this operation */
+ rc = -ENOTSUP;
+ }
+
+ intf_put ( dest );
+ return rc;
+}
#include <ipxe/list.h>
#include <ipxe/tables.h>
+struct interface;
+
/** A hardware device description */
struct device_description {
/** Bus type
/** Declare a root device */
#define __root_device __table_entry ( ROOT_DEVICES, 01 )
+extern struct device * identify_device ( struct interface *intf );
+#define identify_device_TYPE( object_type ) \
+ typeof ( struct device * ( object_type ) )
+
#endif /* _IPXE_DEVICE_H */
--- /dev/null
+#ifndef _IPXE_EDD_H
+#define _IPXE_EDD_H
+
+/** @file
+ *
+ * Enhanced Disk Drive specification
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/interface.h>
+
+/** An EDD host bus type */
+struct edd_host_bus_type {
+ /** Type */
+ uint32_t type;
+} __attribute__ (( packed ));
+
+/** EDD bus type */
+#define EDD_BUS_TYPE_FIXED( a, b, c, d, ... ) \
+ ( ( (a) << 0 ) | ( (b) << 8 ) | ( (c) << 16 ) | ( (d) << 24 ) )
+#define EDD_BUS_TYPE( ... ) \
+ EDD_BUS_TYPE_FIXED ( __VA_ARGS__, ' ', ' ', ' ', ' ' )
+/** EDD PCI bus type */
+#define EDD_BUS_TYPE_PCI EDD_BUS_TYPE ( 'P', 'C', 'I' )
+/** EDD ISA bus type */
+#define EDD_BUS_TYPE_ISA EDD_BUS_TYPE ( 'I', 'S', 'A' )
+/** EDD PCI-X bus type */
+#define EDD_BUS_TYPE_PCIX EDD_BUS_TYPE ( 'P', 'C', 'I', 'X' )
+/** EDD Infiniband bus type */
+#define EDD_BUS_TYPE_IBND EDD_BUS_TYPE ( 'I', 'B', 'N', 'D' )
+/** EDD PCI Express bus type */
+#define EDD_BUS_TYPE_XPRS EDD_BUS_TYPE ( 'X', 'P', 'R', 'S' )
+/** EDD HyperTransport bus type */
+#define EDD_BUS_TYPE_HTPT EDD_BUS_TYPE ( 'H', 'T', 'P', 'T' )
+
+/** An EDD interface type */
+struct edd_interface_type {
+ /** Type */
+ uint64_t type;
+} __attribute__ (( packed ));
+
+/** EDD interface type */
+#define EDD_INTF_TYPE_FIXED( a, b, c, d, e, f, g, h, ... ) \
+ ( ( ( ( uint64_t ) (a) ) << 0 ) | ( ( ( uint64_t ) (b) ) << 8 ) | \
+ ( ( ( uint64_t ) (c) ) << 16 ) | ( ( ( uint64_t ) (d) ) << 24 ) | \
+ ( ( ( uint64_t ) (e) ) << 32 ) | ( ( ( uint64_t ) (f) ) << 40 ) | \
+ ( ( ( uint64_t ) (g) ) << 48 ) | ( ( ( uint64_t ) (h) ) << 56 ) )
+#define EDD_INTF_TYPE( ... ) \
+ EDD_INTF_TYPE_FIXED ( __VA_ARGS__, \
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' )
+/** EDD ATA interface type */
+#define EDD_INTF_TYPE_ATA EDD_INTF_TYPE ( 'A', 'T', 'A' )
+/** EDD ATAPI interface type */
+#define EDD_INTF_TYPE_ATAPI EDD_INTF_TYPE ( 'A', 'T', 'A', 'P', 'I' )
+/** EDD SCSI interface type */
+#define EDD_INTF_TYPE_SCSI EDD_INTF_TYPE ( 'S', 'C', 'S', 'I' )
+/** EDD USB interface type */
+#define EDD_INTF_TYPE_USB EDD_INTF_TYPE ( 'U', 'S', 'B' )
+/** EDD 1394 interface type */
+#define EDD_INTF_TYPE_1394 EDD_INTF_TYPE ( '1', '3', '9', '4' )
+/** EDD Fibre Channel interface type */
+#define EDD_INTF_TYPE_FIBRE EDD_INTF_TYPE ( 'F', 'I', 'B', 'R', 'E' )
+/** EDD I2O interface type */
+#define EDD_INTF_TYPE_I2O EDD_INTF_TYPE ( 'I', '2', 'O' )
+/** EDD RAID interface type */
+#define EDD_INTF_TYPE_RAID EDD_INTF_TYPE ( 'R', 'A', 'I', 'D' )
+/** EDD SATA interface type */
+#define EDD_INTF_TYPE_SATA EDD_INTF_TYPE ( 'S', 'A', 'T', 'A' )
+/** EDD SAS interface type */
+#define EDD_INTF_TYPE_SAS EDD_INTF_TYPE ( 'S', 'A', 'S' )
+
+/** An EDD interface path */
+union edd_interface_path {
+ /** Legacy bus type */
+ struct {
+ /** Base address */
+ uint16_t base;
+ } __attribute__ (( packed )) legacy;
+ /** PCI, PCI-X, PCI Express, or HyperTransport bus type */
+ struct {
+ /** Bus */
+ uint8_t bus;
+ /** Slot */
+ uint8_t slot;
+ /** Function */
+ uint8_t function;
+ /** Channel number */
+ uint8_t channel;
+ } __attribute__ (( packed )) pci;
+ /** Padding */
+ uint8_t pad[8];
+} __attribute__ (( packed ));
+
+/** An EDD device path */
+union edd_device_path {
+ /** ATA interface type */
+ struct {
+ /** Slave */
+ uint8_t slave;
+ } __attribute__ (( packed )) ata;
+ /** ATAPI interface type */
+ struct {
+ /** Slave */
+ uint8_t slave;
+ /** Logical Unit Number */
+ uint8_t lun;
+ } __attribute__ (( packed )) atapi;
+ /** SCSI interface type */
+ struct {
+ /** SCSI ID */
+ uint16_t id;
+ /** Logical Unit Number */
+ uint64_t lun;
+ } __attribute__ (( packed )) scsi;
+ /** USB interface type */
+ struct {
+ /** Serial number */
+ uint64_t serial;
+ } __attribute__ (( packed )) usb;
+ /** IEEE1394 interface type */
+ struct {
+ /** GUID */
+ uint64_t guid;
+ } __attribute__ (( packed )) ieee1394;
+ /** Fibre Channel interface type */
+ struct {
+ /** WWN */
+ uint64_t wwn;
+ /** Logical Unit Number */
+ uint64_t lun;
+ } __attribute__ (( packed )) fibre;
+ /** I2O interface type */
+ struct {
+ /** Identity tag */
+ uint64_t tag;
+ } __attribute__ (( packed )) i2o;
+ /** RAID interface type */
+ struct {
+ /** Array number */
+ uint32_t array;
+ } __attribute__ (( packed )) raid;
+ /** SATA interface type */
+ struct {
+ /** Port number */
+ uint8_t port;
+ /** Port multiplier number */
+ uint8_t multiplier;
+ } __attribute__ (( packed )) sata;
+ /** SAS interface type */
+ struct {
+ /** Address */
+ uint64_t address;
+ } __attribute__ (( packed )) sas;
+ /** Padding */
+ uint8_t pad[16];
+} __attribute__ (( packed ));
+
+/** EDD device path information */
+struct edd_device_path_information {
+ /** Key */
+ uint16_t key;
+ /** Length of this structure */
+ uint8_t len;
+ /** Reserved */
+ uint8_t reserved_a[3];
+ /** Host bus type */
+ struct edd_host_bus_type host_bus_type;
+ /** Interface type */
+ struct edd_interface_type interface_type;
+ /** Interface path */
+ union edd_interface_path interface_path;
+ /** Device path */
+ union edd_device_path device_path;
+ /** Reserved */
+ uint8_t reserved_b;
+ /** Checksum */
+ uint8_t checksum;
+} __attribute__ (( packed ));
+
+/** EDD device path information key */
+#define EDD_DEVICE_PATH_INFO_KEY 0xbedd
+
+extern int edd_describe ( struct interface *intf,
+ struct edd_interface_type *type,
+ union edd_device_path *path );
+#define edd_describe_TYPE( object_type ) \
+ typeof ( int ( object_type, struct edd_interface_type *type, \
+ union edd_device_path *path ) )
+
+#endif /* _IPXE_EDD_H */
#define ERRFILE_blockdev ( ERRFILE_CORE | 0x00120000 )
#define ERRFILE_acpi ( ERRFILE_CORE | 0x00130000 )
#define ERRFILE_null_sanboot ( ERRFILE_CORE | 0x00140000 )
+#define ERRFILE_edd ( ERRFILE_CORE | 0x00150000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )