Index: Makefile.am =================================================================== RCS file: /cvsroot/hurd/hurd-l4/deva/Makefile.am,v retrieving revision 1.2 diff -u -3 -p -u -r1.2 Makefile.am --- Makefile.am 2 Nov 2004 00:19:13 -0000 1.2 +++ Makefile.am 3 Nov 2004 20:09:56 -0000 @@ -31,7 +31,7 @@ deva_SOURCES = $(ARCH_SOURCES) \ output.h output.c \ physmem-user.h physmem-user.c mmap.c malloc-wrap.c \ task-user.h task-user.c \ - deva.h deva.c deva-class.c + deva.h deva.c deva-class.c deva-ide.c # Doug Lea's malloc is included by malloc-wrap.c. EXTRA_deva_SOURCES = malloc.c Index: deva-ide.c =================================================================== RCS file: deva-ide.c diff -N deva-ide.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ deva-ide.c 3 Nov 2004 20:09:56 -0000 @@ -0,0 +1,447 @@ +/* deva-ide.c - A very simple IDE driver. + Written by Sam Mason, based on GPL code by Johan Rydberg. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU Hurd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA.*/ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "deva.h" + +#include "nova-ide.h" + +#include + +/* byte swapping stuff - is this anywhere else? */ +static inline u_int16_t +swab_uint16(u_int16_t x) +{ + return ((x & 0xff) << 8) | ((x >> 8) & 0xff); +} + +#if L4_BYTE_ORDER == L4_LITTLE_ENDIAN +# define leth_swab_uint16(x) (x) +# define beth_swab_uint16(x) swab_uint16(x) +# define htle_swab_uint16(x) (x) +# define htbe_swab_uint16(x) swab_uint16(x) +#elif L4_BYTE_ORDER == L4_BIG_ENDIAN +# define leth_swab_uint16(x) swab_uint16(x) +# define beth_swab_uint16(x) (x) +# define htle_swab_uint16(x) swab_uint16(x) +# define htbe_swab_uint16(x) (x) +#elif +# error Unsupported byte order +#endif + +/* Simple delay function -- just loops and loops. */ +static void +ide_delay(int cnt) +{ + int i; + + for(i = 0; i < (cnt * 100); i++) + ; /* no-op */ +} + +struct idereq +{ + u_int32_t bio_blkno; + u_int8_t bio_cmd; + u_int8_t bio_rnsects; + u_int16_t bio_rcyl; + u_int8_t bio_rhead; + u_int8_t bio_rsect; + u_int8_t bio_error; + u_int8_t bio_flag; +}; + +typedef unsigned short int port_base; + +#define io_write_1(base, off, data) outb((data), (base) + (off)) +#define io_read_1(base, off) inb((base) + (off)) +#define io_read_2(base, off) inw((base) + (off)) + +static pthread_mutex_t ide_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t ide_cond = PTHREAD_COND_INITIALIZER; + +/* Checks if the controler is ready. TIMEOUT is number of retries. */ +static int +controler_ready(port_base cmd, int timeout) +{ + u_int8_t value, mask; + int retries = 1; + + mask = IDE_STATUS_READY | IDE_STATUS_BUSY; + + do + { + value = io_read_1(cmd, IDE_REGISTER_STATUS); + + if((value & mask) == IDE_STATUS_READY) + break; + } + while(!timeout || retries++ < timeout); + + return retries; +} + +/* Probe the controler to see if there's any disks on it. + This is only used before attaching device. */ +static int +probe_controler(port_base cmd, int timeout) +{ + int disk_mask = 3, err; + u_int8_t st0, st1; + + err = controler_ready(cmd, timeout); + if(!err) + { + debug("no controler ready at 0x%x\n", cmd); + return 0; + } + + io_write_1(cmd, IDE_REGISTER_DRIVE, IDE_ADDR_IBM); + ide_delay(100); + st0 = io_read_1(cmd, IDE_REGISTER_STATUS); + + io_write_1(cmd, IDE_REGISTER_DRIVE, IDE_ADDR_IBM | 0x10); + ide_delay(100); + st1 = io_read_1(cmd, IDE_REGISTER_STATUS); + + if(st0 & IDE_STATUS_ERROR) + disk_mask &= ~0x1; + if(st1 & IDE_STATUS_ERROR) + disk_mask &= ~0x2; + + return disk_mask; +} + +struct drive +{ + port_base cmd, aux; + + u_int32_t sc_channel, sc_drive; + + struct idereq bio; + + struct + { + u_int16_t cylinders, heads, sectors; + + } param; +}; + +static void +dump_drive(struct drive * drv) +{ + printf("(rnsects %x) (rsect %x) (rcyl %x) (drive %x) (rhead %x) (cmd %x)\n", + drv->bio.bio_rnsects, + drv->bio.bio_rsect, + drv->bio.bio_rcyl, + drv->sc_drive, + drv->bio.bio_rhead, + drv->bio.bio_cmd); +} + +static int +controler_wait(struct drive * drv, u_int8_t mask, u_int8_t bits, int timeout) +{ + u_int8_t value, err; + + pthread_mutex_lock(&ide_lock); + + while(1) + { + value = io_read_1(drv->cmd, IDE_REGISTER_STATUS); + + if(((value & IDE_STATUS_BUSY) == 0) && ((value & mask) == bits)) + break; + + // TODO: how do we handle timeouts now? + + pthread_cond_wait(&ide_cond, &ide_lock); + } + + pthread_mutex_unlock(&ide_lock); + + if(value & IDE_STATUS_ERROR) + { + err = io_read_1(drv->cmd, IDE_REGISTER_ERROR); + + printf("ide channel %d drive %d: wait: mask ok but error=%x\n", + drv->sc_channel, drv->sc_drive, err); + } + + return 0; +} + +static void +exec_transfer(struct drive * drv) +{ + io_write_1(drv->aux, 0, 0); + io_write_1(drv->cmd, IDE_REGISTER_PRECOMP, 0); + io_write_1(drv->cmd, IDE_REGISTER_NSECTORS, drv->bio.bio_rnsects); + io_write_1(drv->cmd, IDE_REGISTER_SECTOR, drv->bio.bio_rsect); + io_write_1(drv->cmd, IDE_REGISTER_CYLINDER_LOW, drv->bio.bio_rcyl & 0xff); + io_write_1(drv->cmd, IDE_REGISTER_CYLINDER_HIGH, drv->bio.bio_rcyl >> 8); + io_write_1(drv->cmd, IDE_REGISTER_DRIVE, IDE_ADDR_LBA | IDE_ADDR_IBM | (drv->sc_drive << 4) | drv->bio.bio_rhead); + io_write_1(drv->cmd, IDE_REGISTER_COMMAND, drv->bio.bio_cmd); +} + +/* Initalise BIO for a disk transfer */ +static int +init_transfer(struct drive * drv, u_int32_t start, u_int16_t count, int read_p) +{ + u_int32_t temp; + + drv->bio.bio_rcyl = start / (drv->param.heads * drv->param.sectors); + temp = start % (drv->param.heads * drv->param.sectors); + drv->bio.bio_rhead = temp / drv->param.sectors; + drv->bio.bio_rsect = temp % drv->param.sectors + 1; + drv->bio.bio_rnsects = count; + drv->bio.bio_cmd = read_p ? IDE_COMMAND_READ : IDE_COMMAND_WRITE; + + return 0; +} + +/* Get ATA controller information */ +static void +request_ata_params(struct drive * drv) +{ + /* Initialize block I/O transfer thingy. */ + memset(&drv->bio, 0, sizeof(drv->bio)); + drv->bio.bio_cmd = 0xEC; // 0xec = IDENTIFY DEVICE + drv->bio.bio_rnsects = 1; + exec_transfer(drv); +} + +/* transfer requested data off the device */ +static int +transfer_intr(struct drive * drv, void * buf, u_int16_t len, const char * msg) +{ + u_int16_t * p; + int err, n = len * 256; + + /* Wait for data to be ready. */ + err = controler_wait(drv, IDE_STATUS_DRQ, IDE_STATUS_DRQ, 6000); + if(err) + { + printf("ide channel %d drive %d: %s\n", + drv->sc_channel, drv->sc_drive, msg); + + return EIO; + } + + p = (u_int16_t *)buf; + while(n-- > 0) + *p++ = htbe_swab_uint16(io_read_2(drv->cmd, IDE_REGISTER_DATA)); + + return 0; +} + +static void test_chan(port_base cmd, port_base aux, int chan) +{ + static u_int8_t buf[512]; + + int err, i, disk_mask; + + disk_mask = probe_controler(cmd, 12000); + + for(i = 0; i < 2; i++) + { + struct drive drv; + + if((disk_mask & (1 << i)) == 0) + { + printf("Ignoring channel %i device %i\n", chan, i); + + continue; + } + + drv.cmd = cmd; + drv.aux = aux; + drv.sc_channel = chan; + drv.sc_drive = i; + + request_ata_params(&drv); + err = transfer_intr(&drv, buf, 1, "while fetching device parameters"); + + if(err == 0) + { + struct ata_params * prm = (struct ata_params *)buf; + + /* + * Slightly grim, but printf doesn't allow us + * to specifify field widths yet + */ + prm->atap_model[39] = 0; + + printf("ATA Params\n"); + printf(" cylinders : %i\n", beth_swab_uint16(prm->atap_cylinders)); + printf(" heads : %i\n", beth_swab_uint16(prm->atap_heads)); + printf(" sectors : %i\n", beth_swab_uint16(prm->atap_sectors)); + printf(" capability : %x\n", beth_swab_uint16(prm->atap_capabilities1)); + printf(" capability : %x\n", beth_swab_uint16(prm->atap_capabilities2)); + printf(" lcyliners : %i\n", beth_swab_uint16(prm->atap_curcylinders)); + printf(" lheads : %i\n", beth_swab_uint16(prm->atap_curheads)); + printf(" lsectors : %i\n", beth_swab_uint16(prm->atap_cursectors)); + + printf(" model : %s\n", prm->atap_model); + + /* remember drive layout */ + drv.param.cylinders = beth_swab_uint16(prm->atap_cylinders); + drv.param.heads = beth_swab_uint16(prm->atap_heads); + drv.param.sectors = beth_swab_uint16(prm->atap_sectors); + + /* TODO: probably need to remember lots more + * than this */ + + /* + * This is basically what's needed for a + * normal read of the disk + */ + init_transfer(&drv, 0, 1, 1); + exec_transfer(&drv); + err = transfer_intr(&drv, buf, 1, "while reading MBR"); + + printf("Result of MBR: %i (%x %x %x %x))\n", err, + buf[0], buf[1], buf[2], buf[3]); + } + else + printf("Unable to fetch ATA params (%i)\n", err); + } +} + +static void * +ide_irq_handler (void *unused) +{ + l4_word_t result; + l4_thread_id_t irq; + l4_msg_tag_t tag; + +#define IDE_IRQ 14 + + irq = l4_global_id(IDE_IRQ, 1); + result = wortel_thread_control(irq, irq, l4_nilthread, l4_myself (), + (void *) -1); + if (result) + panic ("setting irq pager failed: %i", result); + +#define l4_reply_receive(tid) \ + ({ l4_thread_id_t dummy; \ + l4_ipc(tid, tid, l4_timeouts(L4_ZERO_TIME, L4_NEVER), &dummy); }) + + tag = l4_receive(irq); + + while(1) + { + pthread_mutex_lock(&ide_lock); + pthread_cond_broadcast(&ide_cond); + pthread_mutex_unlock(&ide_lock); + + l4_load_mr (0, 0); + l4_reply_receive (irq); + } +} + +struct hdd +{ + int bar; /* 512 octet buffer here for for transfer? */ +}; +typedef struct hdd *hdd_t; + +static struct hurd_cap_class hdd_class; + +static void +hdd_reinit(hurd_cap_class_t cap_class, hurd_cap_obj_t obj) +{ + hdd_t hdd = hurd_cap_obj_to_user(hdd_t, obj); + + /* FIXME: Release resources. */ +} + +error_t +hdd_demuxer(hurd_cap_rpc_context_t ctx) +{ + error_t err = 0; + + switch(l4_msg_label(ctx->msg)) + { + default: + err = EOPNOTSUPP; + } + + return err; +} + +/* Initialize the deva class subsystem. */ +error_t +deva_hdd_init() +{ + error_t err; + l4_thread_id_t irq_handler_tid; + pthread_t irq_handler; + + printf("\n\nhello world from deva-ide\n"); + + irq_handler_tid = pthread_pool_get_np (); + if (irq_handler_tid == l4_nilthread) + panic ("Can not create the irq handler thread"); + + err = pthread_create_from_l4_tid_np (&irq_handler, NULL, + irq_handler_tid, ide_irq_handler, + NULL); + if (err) + panic ("Can not create the irq handler thread: %i", err); + + pthread_detach (irq_handler); + + test_chan(IDE_IOBASE_PRIMARY_LOW, IDE_IOBASE_PRIMARY_AUX, 0); + test_chan(IDE_IOBASE_SECONDARY_LOW, IDE_IOBASE_SECONDARY_AUX, 1); + + return hurd_cap_class_init(&hdd_class, hdd_t, + NULL, NULL, hdd_reinit, NULL, + hdd_demuxer); +} + +/* Allocate a new deva object. The object returned is locked and has + one reference. */ +error_t +deva_hdd_alloc(hurd_cap_obj_t *r_obj) +{ + error_t err; + hurd_cap_obj_t obj; + hdd_t hdd; + + err = hurd_cap_class_alloc(&hdd_class, &obj); + if(err) + return err; + + hdd = hurd_cap_obj_to_user(hdd_t, obj); + + /* FIXME: Add some stuff. */ + + *r_obj = obj; + return 0; +} Index: deva.c =================================================================== RCS file: /cvsroot/hurd/hurd-l4/deva/deva.c,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 deva.c --- deva.c 2 Nov 2004 03:56:32 -0000 1.3 +++ deva.c 3 Nov 2004 20:09:56 -0000 @@ -223,6 +223,10 @@ main (int argc, char *argv[]) if (err) panic ("deva_class_init: %i\n", err); + err = deva_hdd_init (); + if (err) + panic("deva_class_init: %i\n", err); + err = hurd_cap_bucket_create (&bucket); if (err) panic ("bucket_create: %i\n", err); Index: deva.h =================================================================== RCS file: /cvsroot/hurd/hurd-l4/deva/deva.h,v retrieving revision 1.1 diff -u -3 -p -u -r1.1 deva.h --- deva.h 28 Oct 2004 04:12:17 -0000 1.1 +++ deva.h 3 Nov 2004 20:09:56 -0000 @@ -50,3 +50,7 @@ error_t deva_class_init (); /* Allocate a new deva object. The object returned is locked and has one reference. */ error_t deva_alloc (hurd_cap_obj_t *r_obj); + + +error_t deva_hdd_init (); +error_t deva_hdd_alloc (hurd_cap_obj_t *r_obj); Index: nova-ide.h =================================================================== RCS file: nova-ide.h diff -N nova-ide.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nova-ide.h 3 Nov 2004 20:09:56 -0000 @@ -0,0 +1,225 @@ +/* IDE driver. + Copyright 2002 Johan Rydberg, address@hidden + +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 +(at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* I/O registers bases. */ + +#define IDE_IOBASE_PRIMARY_LOW 0x1F0 +#define IDE_IOBASE_PRIMARY_AUX 0x3F6 +#define IDE_IOBASE_PRIMARY_LENGTH 8 + +#define IDE_IOBASE_SECONDARY_LOW 0x170 +#define IDE_IOBASE_SECONDARY_AUX 0x376 +#define IDE_IOBASE_SECONDARY_LENGTH 8 + +/* I/O registers. */ + +#define IDE_REGISTER_DATA 0 +#define IDE_REGISTER_ERROR 1 +#define IDE_REGISTER_NSECTORS 2 +#define IDE_REGISTER_SECTOR 3 +#define IDE_REGISTER_CYLINDER_LOW 4 +#define IDE_REGISTER_CYLINDER_HIGH 5 +#define IDE_REGISTER_DRIVE 6 +#define IDE_REGISTER_STATUS 7 +#define IDE_REGISTER_COMMAND IDE_REGISTER_STATUS +#define IDE_REGISTER_PRECOMP IDE_REGISTER_ERROR +#define IDE_REGISTER_AUX IDE_REGISTER_DATA + +/* Commands (sent to IDE_REGISTER_COMMAND). */ + +#define IDE_COMMAND_RESTORE 0x10 +#define IDE_COMMAND_READ 0x20 +#define IDE_COMMAND_WRITE 0x30 +#define IDE_COMMAND_VERIFY 0x40 +#define IDE_COMMAND_FORMAT 0x50 +#define IDE_COMMAND_INIT 0x60 +#define IDE_COMMAND_SEEK 0x70 +#define IDE_COMMAND_DIAGNOSE 0x90 +#define IDE_COMMAND_SPECIFY 0x91 +#define IDE_COMMAND_READMULTI 0xc4 + +/* Status. */ + +#define IDE_STATUS_ERROR 0x01 +#define IDE_STATUS_INDEX 0x02 +#define IDE_STATUS_ECC 0x04 +#define IDE_STATUS_DRQ 0x08 +#define IDE_STATUS_SEEK 0x10 +#define IDE_STATUS_WRERR 0x20 +#define IDE_STATUS_READY 0x40 +#define IDE_STATUS_BUSY 0x80 + +#define IDE_ADDR_IBM 0xa0 /* forced to 512 byte sector, ecc */ +#define IDE_ADDR_CHS 0x00 /* cylinder/head/sector addressing */ +#define IDE_ADDR_LBA 0x40 /* logical block addressing */ + +/* ATA parameter structure. */ + +struct ata_params { + /* drive info */ + u_int16_t atap_config; /* 0: general configuration */ +#define IDE_CFG_ATAPI_MASK 0xc000 +#define IDE_CFG_ATAPI 0x8000 +#define ATA_CFG_REMOVABLE 0x0080 +#define ATA_CFG_FIXED 0x0040 +#define ATAPI_CFG_TYPE_MASK 0x1f00 +#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8) +#define ATAPI_CFG_REMOV 0x0080 +#define ATAPI_CFG_DRQ_MASK 0x0060 +#define ATAPI_CFG_STD_DRQ 0x0000 +#define ATAPI_CFG_IRQ_DRQ 0x0020 +#define ATAPI_CFG_ACCEL_DRQ 0x0040 +#define ATAPI_CFG_CMD_MASK 0x0003 +#define ATAPI_CFG_CMD_12 0x0000 +#define ATAPI_CFG_CMD_16 0x0001 + /* words 1-9 are ATA only */ + u_int16_t atap_cylinders; /* 1: # of non-removable cylinders */ + u_int16_t __reserved1; + u_int16_t atap_heads; /* 3: # of heads */ + u_int16_t __retired1[2]; /* 4-5: # of unform. bytes/track */ + u_int16_t atap_sectors; /* 6: # of sectors */ + u_int16_t __retired2[3]; + + u_int8_t atap_serial[20]; /* 10-19: serial number */ + u_int16_t __retired3[2]; + u_int16_t __obsolete1; + u_int8_t atap_revision[8]; /* 23-26: firmware revision */ + u_int8_t atap_model[40]; /* 27-46: model number */ + u_int16_t atap_multi; /* 47: maximum sectors per irq (ATA) */ + u_int16_t __reserved2; + u_int16_t atap_capabilities1; /* 49: capability flags */ +#define IDE_CAP_IORDY 0x0800 +#define IDE_CAP_IORDY_DSBL 0x0400 +#define IDE_CAP_LBA 0x0200 +#define IDE_CAP_DMA 0x0100 +#define ATA_CAP_STBY 0x2000 +#define ATAPI_CAP_INTERL_DMA 0x8000 +#define ATAPI_CAP_CMD_QUEUE 0x4000 +#define ATAPI_CAP_OVERLP 0X2000 +#define ATAPI_CAP_ATA_RST 0x1000 + u_int16_t atap_capabilities2; /* 50: capability flags (ATA) */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_int8_t __junk2; + u_int8_t atap_oldpiotiming; /* 51: old PIO timing mode */ + u_int8_t __junk3; + u_int8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */ +#else + u_int8_t atap_oldpiotiming; /* 51: old PIO timing mode */ + u_int8_t __junk2; + u_int8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */ + u_int8_t __junk3; +#endif + u_int16_t atap_extensions; /* 53: extentions supported */ +#define IDE_EXT_UDMA_MODES 0x0004 +#define IDE_EXT_MODES 0x0002 +#define IDE_EXT_GEOM 0x0001 + /* words 54-62 are ATA only */ + u_int16_t atap_curcylinders; /* 54: current logical cyliners */ + u_int16_t atap_curheads; /* 55: current logical heads */ + u_int16_t atap_cursectors; /* 56: current logical sectors/tracks */ + u_int16_t atap_curcapacity[2]; /* 57-58: current capacity */ + u_int16_t atap_curmulti; /* 59: current multi-sector setting */ +#define IDE_MULTI_VALID 0x0100 +#define IDE_MULTI_MASK 0x00ff + u_int16_t atap_capacity[2]; /* 60-61: total capacity (LBA only) */ + u_int16_t __retired4; +#if BYTE_ORDER == LITTLE_ENDIAN + u_int8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */ + u_int8_t atap_dmamode_act; /* multiword DMA mode active */ + u_int8_t atap_piomode_supp; /* 64: PIO mode supported */ + u_int8_t __junk4; +#else + u_int8_t atap_dmamode_act; /* multiword DMA mode active */ + u_int8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */ + u_int8_t __junk4; + u_int8_t atap_piomode_supp; /* 64: PIO mode supported */ +#endif + u_int16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */ + u_int16_t atap_dmatiming_recom; /* 66: recomended DMA cycle time */ + u_int16_t atap_piotiming; /* 67: mini PIO cycle time without FC */ + u_int16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */ + u_int16_t __reserved3[2]; + + /* words 71-72 are ATAPI only */ + u_int16_t atap_pkt_br; /* 71: time (ns) to bus release */ + u_int16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */ + u_int16_t __reserved4[2]; + u_int16_t atap_queuedepth; /* 75: */ +#define IDE_QUEUE_DEPTH_MASK 0x0F + u_int16_t __reserved5[4]; + u_int16_t atap_ata_major; /* 80: Major version number */ +#define IDE_VER_ATA1 0x0002 +#define IDE_VER_ATA2 0x0004 +#define IDE_VER_ATA3 0x0008 +#define IDE_VER_ATA4 0x0010 +#define IDE_VER_ATA5 0x0020 + u_int16_t atap_ata_minor; /* 81: Minor version number */ + u_int16_t atap_cmd_set1; /* 82: command set suported */ +#define IDE_CMD1_NOP 0x4000 +#define IDE_CMD1_RB 0x2000 +#define IDE_CMD1_WB 0x1000 +#define IDE_CMD1_HPA 0x0400 +#define IDE_CMD1_DVRST 0x0200 +#define IDE_CMD1_SRV 0x0100 +#define IDE_CMD1_RLSE 0x0080 +#define IDE_CMD1_AHEAD 0x0040 +#define IDE_CMD1_CACHE 0x0020 +#define IDE_CMD1_PKT 0x0010 +#define IDE_CMD1_PM 0x0008 +#define IDE_CMD1_REMOV 0x0004 +#define IDE_CMD1_SEC 0x0002 +#define IDE_CMD1_SMART 0x0001 + u_int16_t atap_cmd_set2; /* 83: command set suported */ +#define IDE_CMD2_RMSN 0x0010 +#define IDE_CMD2_DM 0x0001 +#define ATA_CMD2_APM 0x0008 +#define ATA_CMD2_CFA 0x0004 +#define ATA_CMD2_RWQ 0x0002 + u_int16_t atap_cmd_ext; /* 84: command/features supp. ext. */ + u_int16_t atap_cmd1_en; /* 85: cmd/features enabled */ + + /* bits are the same as atap_cmd_set1 */ + u_int16_t atap_cmd2_en; /* 86: cmd/features enabled */ + + /* bits are the same as atap_cmd_set2 */ + u_int16_t atap_cmd_def; /* 87: cmd/features default */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_int8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */ + u_int8_t atap_udmamode_act; /* Ultra-DMA mode active */ +#else + u_int8_t atap_udmamode_act; /* Ultra-DMA mode active */ + u_int8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */ +#endif + + /* 89-92 are ATA-only */ + u_int16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */ + u_int16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */ + u_int16_t atap_apm_val; /* 91: current APM value */ + u_int16_t __reserved6[35]; /* 92-126: reserved */ + u_int16_t atap_rmsn_supp; /* 127: remov. media status notif. */ +#define IDE_RMSN_SUPP_MASK 0x0003 +#define IDE_RMSN_SUPP 0x0001 + u_int16_t atap_sec_st; /* 128: security status */ +#define IDE_SEC_LEV_MAX 0x0100 +#define IDE_SEC_ESE_SUPP 0x0020 +#define IDE_SEC_EXP 0x0010 +#define IDE_SEC_FROZEN 0x0008 +#define IDE_SEC_LOCKED 0x0004 +#define IDE_SEC_EN 0x0002 +#define IDE_SEC_SUPP 0x0001 + u_int8_t pad[254]; +};