ata.c revision 8a2c7cae7578acfb7c77a510f12fabee2670e31c
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Copyright (C) 2006-2012 Oracle Corporation
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * available from http://www.virtualbox.org. This file is free software;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * General Public License (GPL) as published by the Free Software
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * --------------------------------------------------------------------
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This code is based on:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * Copyright (C) 2002 MandrakeSoft S.A.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync *
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * MandrakeSoft S.A.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * 43, rue d'Aboukir
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * 75002 Paris - France
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * http://www.linux-mandrake.com/
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * http://www.mandrakesoft.com/
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync *
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * This library is free software; you can redistribute it and/or
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * modify it under the terms of the GNU Lesser General Public
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * License as published by the Free Software Foundation; either
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * version 2 of the License, or (at your option) any later version.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This library is distributed in the hope that it will be useful,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Lesser General Public License for more details.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
032a52c5b2984e26e84c2961f8f7f98a3954c8f2vboxsync * You should have received a copy of the GNU Lesser General Public
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * License along with this library; if not, write to the Free Software
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <stdint.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <stdarg.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include "inlines.h"
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include "biosint.h"
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include "ebda.h"
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include "ata.h"
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#if DEBUG_ATA
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync# define BX_DEBUG_ATA(...) BX_DEBUG(__VA_ARGS__)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#else
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync# define BX_DEBUG_ATA(...)
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync#endif
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync// ---------------------------------------------------------------------------
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync// Start of ATA/ATAPI Driver
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync// ---------------------------------------------------------------------------
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsyncvoid insw_discard(unsigned nwords, unsigned port);
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync#pragma aux insw_discard = \
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync ".286" \
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync "again:" \
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync "in ax,dx" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "loop again" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync parm [cx] [dx] modify exact [cx ax] nomemory;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsyncvoid insd_discard(unsigned ndwords, unsigned port);
044af0d1e6474076366759db86f101778c5f20ccvboxsync#pragma aux insd_discard = \
044af0d1e6474076366759db86f101778c5f20ccvboxsync ".386" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "push eax" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "again:" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "in eax,dx" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "loop again" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync "pop eax" \
044af0d1e6474076366759db86f101778c5f20ccvboxsync parm [cx] [dx] modify exact [cx] nomemory;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync// ---------------------------------------------------------------------------
044af0d1e6474076366759db86f101778c5f20ccvboxsync// ATA/ATAPI driver : initialization
044af0d1e6474076366759db86f101778c5f20ccvboxsync// ---------------------------------------------------------------------------
044af0d1e6474076366759db86f101778c5f20ccvboxsyncvoid BIOSCALL ata_init(void)
044af0d1e6474076366759db86f101778c5f20ccvboxsync{
044af0d1e6474076366759db86f101778c5f20ccvboxsync uint8_t channel, device;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bio_dsk_t __far *bios_dsk;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync // Channels info init.
044af0d1e6474076366759db86f101778c5f20ccvboxsync for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->channels[channel].iface = ATA_IFACE_NONE;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->channels[channel].iobase1 = 0x0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->channels[channel].iobase2 = 0x0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->channels[channel].irq = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // Devices info init.
044af0d1e6474076366759db86f101778c5f20ccvboxsync for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].type = DSK_TYPE_NONE;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].device = DSK_DEVICE_NONE;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].removable = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].lock = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].mode = ATA_MODE_NONE;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].blksize = 0x200;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].translation = GEO_TRANSLATION_NONE;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].lchs.heads = 0;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].lchs.cylinders = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->devices[device].lchs.spt = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->devices[device].pchs.heads = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->devices[device].pchs.cylinders = 0;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].pchs.spt = 0;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].sectors = 0;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // hdidmap and cdidmap init.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->hdidmap[device] = BX_MAX_STORAGE_DEVICES;
044af0d1e6474076366759db86f101778c5f20ccvboxsync bios_dsk->cdidmap[device] = BX_MAX_STORAGE_DEVICES;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->hdcount = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync bios_dsk->cdcount = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync}
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync// ---------------------------------------------------------------------------
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync// ATA/ATAPI driver : software reset
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync// ---------------------------------------------------------------------------
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync// ATA-3
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync// 8.2.1 Software reset - Device 0
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsyncvoid ata_reset(uint16_t device)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync{
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync uint16_t iobase1, iobase2;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync uint8_t channel, slave, sn, sc;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync uint16_t max;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync uint16_t pdelay;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bio_dsk_t __far *bios_dsk;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync channel = device / 2;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync slave = device % 2;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync iobase1 = bios_dsk->channels[channel].iobase1;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync iobase2 = bios_dsk->channels[channel].iobase2;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync // Reset
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync // 8.2.1 (a) -- set SRST in DC
a1df400bbe9d64aad400442e56eb637019300a5evboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync // 8.2.1 (b) -- wait for BSY
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync max=0xff;
044af0d1e6474076366759db86f101778c5f20ccvboxsync while(--max>0) {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uint8_t status = inb(iobase1+ATA_CB_STAT);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if ((status & ATA_CB_STAT_BSY) != 0)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 8.2.1 (f) -- clear SRST
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync if (bios_dsk->devices[device].type != DSK_TYPE_NONE) {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync // 8.2.1 (g) -- check for sc==sn==0x01
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // select device
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync sc = inb(iobase1+ATA_CB_SC);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync sn = inb(iobase1+ATA_CB_SN);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if ( (sc==0x01) && (sn==0x01) ) {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 8.2.1 (h) -- wait for not BSY
044af0d1e6474076366759db86f101778c5f20ccvboxsync max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync while(--max>0) {
044af0d1e6474076366759db86f101778c5f20ccvboxsync uint8_t status = inb(iobase1+ATA_CB_STAT);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if ((status & ATA_CB_STAT_BSY) == 0)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pdelay=0xffff;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync while (--pdelay>0) {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /* nothing */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync }
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // 8.2.1 (i) -- wait for DRDY
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync max = 0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync while(--max>0) {
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync uint8_t status = inb(iobase1+ATA_CB_STAT);
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync if ((status & ATA_CB_STAT_RDY) != 0)
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync break;
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync }
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // Enable interrupts
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync}
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync// ---------------------------------------------------------------------------
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync// ATA/ATAPI driver : execute a data-in command
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync// ---------------------------------------------------------------------------
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // returns
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // 0 : no error
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // 1 : BUSY bit set
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // 2 : read error
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync // 3 : expected DRQ=1
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 4 : no sectors left to read/verify
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 5 : more sectors to read/verify
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 6 : no sectors left to write
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // 7 : more sectors to write
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncuint16_t ata_cmd_data_in(bio_dsk_t __far *bios_dsk, uint16_t command, uint16_t count)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync{
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint32_t lba;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t iobase1, iobase2, blksize, mult_blk_cnt;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t cylinder;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t head;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t sector;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t device;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t channel, slave;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t status, mode;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync char __far *buffer;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync device = bios_dsk->drqp.dev_id;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync channel = device / 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync slave = device % 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync iobase1 = bios_dsk->channels[channel].iobase1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync iobase2 = bios_dsk->channels[channel].iobase2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync mode = bios_dsk->devices[device].mode;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize = bios_dsk->devices[device].blksize;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (blksize == 0) { /* If transfer size is exactly 64K */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (mode == ATA_MODE_PIO32)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize = 0x4000;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync else
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize = 0x8000;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } else {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (mode == ATA_MODE_PIO32)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize >>= 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync else
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize >>= 1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync status = inb(iobase1 + ATA_CB_STAT);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (status & ATA_CB_STAT_BSY)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync BX_DEBUG_ATA("%s: disk busy\n", __func__);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return 1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync lba = bios_dsk->drqp.lba;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync buffer = bios_dsk->drqp.buffer;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync sector = bios_dsk->drqp.sector;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync cylinder = bios_dsk->drqp.cylinder;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync head = bios_dsk->drqp.head;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync // sector will be 0 only on lba access. Convert to lba-chs
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if (sector == 0) {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if (lba + count >= 268435456)
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync sector = (lba & 0xff000000L) >> 24;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync cylinder = 0; /* The parameter lba is just a 32 bit value. */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync outb(iobase1 + ATA_CB_SN, sector);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_CH, cylinder >> 8);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Leave the bottom 24 bits as is, they are treated correctly by the
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * LBA28 code path. */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync lba &= 0xffffff;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync sector = (uint16_t) (lba & 0x000000ffL);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync lba >>= 8;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync cylinder = (uint16_t) (lba & 0x0000ffffL);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync lba >>= 16;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync head = ((uint16_t) (lba & 0x0000000fL)) | 0x40;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_FR, 0x00);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_SC, count);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_SN, sector);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_CH, cylinder >> 8);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (uint8_t) head );
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync outb(iobase1 + ATA_CB_CMD, command);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync mult_blk_cnt = count;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync count = 1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } else {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync mult_blk_cnt = 1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync while (1) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync status = inb(iobase1 + ATA_CB_STAT);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( !(status & ATA_CB_STAT_BSY) )
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync break;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (status & ATA_CB_STAT_ERR) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync BX_DEBUG_ATA("%s: read error\n", __func__);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } else if ( !(status & ATA_CB_STAT_DRQ) ) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync return 3;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // FIXME : move seg/off translation here
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int_enable(); // enable higher priority interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync while (1) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // adjust if there will be an overrun. 2K max sector size
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (FP_OFF(buffer) >= 0xF800)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync buffer = MK_FP(FP_SEG(buffer) + 0x80, FP_OFF(buffer) - 0x800);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (mode == ATA_MODE_PIO32) {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync buffer = rep_insd(buffer, blksize, iobase1);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync } else {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync buffer = rep_insw(buffer, blksize, iobase1);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->drqp.trsfsectors += mult_blk_cnt;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync count--;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync while (1) {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync status = inb(iobase1 + ATA_CB_STAT);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if ( !(status & ATA_CB_STAT_BSY) )
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync break;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if (count == 0) {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync != ATA_CB_STAT_RDY ) {
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync BX_DEBUG_ATA("%s: no sectors left (status %02x)\n", __func__, (unsigned) status);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return 4;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync break;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync else {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync BX_DEBUG_ATA("%s: more sectors left (status %02x)\n", __func__, (unsigned) status);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return 5;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync continue;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return 0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync}
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync// ---------------------------------------------------------------------------
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync// ATA/ATAPI driver : device detection
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync// ---------------------------------------------------------------------------
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncvoid BIOSCALL ata_detect(void)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync{
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t ebda_seg = read_word(0x0040,0x000E);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t hdcount, cdcount, device, type;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t buffer[0x0200];
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bio_dsk_t __far *bios_dsk;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk = ebda_seg :> &EbdaData->bdisk;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if BX_MAX_ATA_INTERFACES > 0
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[0].iface = ATA_IFACE_ISA;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[0].iobase1 = 0x1f0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[0].iobase2 = 0x3f0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[0].irq = 14;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if BX_MAX_ATA_INTERFACES > 1
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[1].iface = ATA_IFACE_ISA;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[1].iobase1 = 0x170;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[1].iobase2 = 0x370;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[1].irq = 15;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if 0 //@todo - temporarily removed to avoid conflict with AHCI
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if BX_MAX_ATA_INTERFACES > 2
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[2].iface = ATA_IFACE_ISA;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[2].iobase1 = 0x1e8;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[2].iobase2 = 0x3e0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[2].irq = 12;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if BX_MAX_ATA_INTERFACES > 3
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[3].iface = ATA_IFACE_ISA;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[3].iobase1 = 0x168;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[3].iobase2 = 0x360;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->channels[3].irq = 11;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#if BX_MAX_ATA_INTERFACES > 4
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#error Please fill the ATA interface informations
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#endif
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Device detection
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync hdcount = cdcount = 0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync for (device = 0; device < BX_MAX_ATA_DEVICES; device++) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t iobase1, iobase2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t channel, slave;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t sc, sn, cl, ch, st;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync channel = device / 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync slave = device % 2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync iobase1 = bios_dsk->channels[channel].iobase1;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync iobase2 = bios_dsk->channels[channel].iobase2;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Disable interrupts
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Look for device
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SC, 0x55);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SN, 0xaa);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SC, 0xaa);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SN, 0x55);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SC, 0x55);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_SN, 0xaa);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // If we found something
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sc = inb(iobase1+ATA_CB_SC);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sn = inb(iobase1+ATA_CB_SN);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( (sc == 0x55) && (sn == 0xaa) ) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].type = DSK_TYPE_UNKNOWN;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // reset the channel
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync ata_reset(device);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // check for ATA or ATAPI
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sc = inb(iobase1+ATA_CB_SC);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sn = inb(iobase1+ATA_CB_SN);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ((sc==0x01) && (sn==0x01)) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync cl = inb(iobase1+ATA_CB_CL);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync ch = inb(iobase1+ATA_CB_CH);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync st = inb(iobase1+ATA_CB_STAT);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ((cl==0x14) && (ch==0xeb)) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].type = DSK_TYPE_ATAPI;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].type = DSK_TYPE_ATA;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync } else if ((cl==0xff) && (ch==0xff)) {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync bios_dsk->devices[device].type = DSK_TYPE_NONE;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Enable interrupts
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync type = bios_dsk->devices[device].type;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Now we send a IDENTIFY command to ATA device
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (type == DSK_TYPE_ATA) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint32_t sectors;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t cylinders, heads, spt, blksize;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync chs_t lgeo;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t chsgeo_base;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t removable, mode;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync //Temporary values to do the transfer
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].device = DSK_DEVICE_HD;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].mode = ATA_MODE_PIO16;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->drqp.buffer = buffer;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->drqp.dev_id = device;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
a1df400bbe9d64aad400442e56eb637019300a5evboxsync if (ata_cmd_data_in(bios_dsk, ATA_CMD_IDENTIFY_DEVICE, 1) !=0 )
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync BX_PANIC("ata-detect: Failed to detect ATA device\n");
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync removable = (*(buffer+0) & 0x80) ? 1 : 0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync mode = *(buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync blksize = 512; /* There is no sector size field any more. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync cylinders = *(uint16_t *)(buffer+(1*2)); // word 1
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync heads = *(uint16_t *)(buffer+(3*2)); // word 3
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync spt = *(uint16_t *)(buffer+(6*2)); // word 6
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sectors = *(uint32_t *)(buffer+(60*2)); // word 60 and word 61
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /** @todo update sectors to be a 64 bit number (also lba...). */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (sectors == 0x0FFFFFFF) /* For disks bigger than ~128GB */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync sectors = *(uint32_t *)(buffer+(100*2)); // words 100 to 103 (someday)
a1df400bbe9d64aad400442e56eb637019300a5evboxsync switch (device)
a1df400bbe9d64aad400442e56eb637019300a5evboxsync {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync case 0:
a1df400bbe9d64aad400442e56eb637019300a5evboxsync chsgeo_base = 0x1e;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync break;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync case 1:
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync chsgeo_base = 0x26;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync break;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync case 2:
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync chsgeo_base = 0x67;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync break;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync case 3:
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync chsgeo_base = 0x70;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync break;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync default:
a1df400bbe9d64aad400442e56eb637019300a5evboxsync chsgeo_base = 0;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (chsgeo_base)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync lgeo.cylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base + 1) << 8);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync lgeo.heads = inb_cmos(chsgeo_base + 2);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync lgeo.spt = inb_cmos(chsgeo_base + 7);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync else
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync set_geom_lba(&lgeo, sectors); /* Default EDD-style translated LBA geometry. */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
a1df400bbe9d64aad400442e56eb637019300a5evboxsync BX_INFO("ata%d-%d: PCHS=%u/%u/%u LCHS=%u/%u/%u\n", channel, slave,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].device = DSK_DEVICE_HD;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].removable = removable;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].mode = mode;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].blksize = blksize;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].pchs.heads = heads;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].pchs.cylinders = cylinders;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].pchs.spt = spt;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].sectors = sectors;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].lchs = lgeo;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (device < 2)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t sum, i;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync fdpt_t __far *fdpt;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (device == 0)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync fdpt = ebda_seg :> &EbdaData->fdpt0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync else
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt = ebda_seg :> &EbdaData->fdpt1;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
044af0d1e6474076366759db86f101778c5f20ccvboxsync * to be done at POST time with lots of ugly assembler code, which
044af0d1e6474076366759db86f101778c5f20ccvboxsync * isn't worth the effort of converting from AMI to Award CMOS
044af0d1e6474076366759db86f101778c5f20ccvboxsync * format. Just do it here. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->lcyl = lgeo.cylinders;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->lhead = lgeo.heads;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->sig = 0xa0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->spt = spt;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->cyl = cylinders;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->head = heads;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->lspt = spt;
044af0d1e6474076366759db86f101778c5f20ccvboxsync sum = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync for (i = 0; i < 0xf; i++)
044af0d1e6474076366759db86f101778c5f20ccvboxsync sum += *((uint8_t __far *)fdpt + i);
044af0d1e6474076366759db86f101778c5f20ccvboxsync sum = -sum;
044af0d1e6474076366759db86f101778c5f20ccvboxsync fdpt->csum = sum;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // fill hdidmap
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->hdidmap[hdcount] = device;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync hdcount++;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Now we send an IDENTIFY command to ATAPI device
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (type == DSK_TYPE_ATAPI) {
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint8_t type, removable, mode;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync uint16_t blksize;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync // Temporary values to do the transfer
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].device = DSK_DEVICE_CDROM;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->devices[device].mode = ATA_MODE_PIO16;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->drqp.buffer = buffer;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync bios_dsk->drqp.dev_id = device;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (ata_cmd_data_in(bios_dsk, ATA_CMD_IDENTIFY_PACKET, 1) != 0)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync type = *(buffer+1) & 0x1f;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync removable = (*(buffer+0) & 0x80) ? 1 : 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync mode = *(buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync blksize = 2048;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->devices[device].device = type;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->devices[device].removable = removable;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->devices[device].mode = mode;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->devices[device].blksize = blksize;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // fill cdidmap
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->cdidmap[cdcount] = device;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync cdcount++;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint32_t sizeinmb;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t ataversion;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint8_t version, model[41];
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync int i;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync switch (type) {
611e5e148a74d4b54cf76c97e4d36acaa816d8c0vboxsync case DSK_TYPE_ATA:
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync sizeinmb = bios_dsk->devices[device].sectors;
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync sizeinmb >>= 11;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync case DSK_TYPE_ATAPI:
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // Read ATA/ATAPI version
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync ataversion = ((uint16_t)(*(buffer+161))<<8) | *(buffer+160);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync for (version = 15; version > 0; version--) {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if ((ataversion & (1 << version)) !=0 )
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // Read model name
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync for (i = 0; i < 20; i++ ) {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync *(model+(i*2)) = *(buffer+(i*2)+54+1);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync *(model+(i*2)+1) = *(buffer+(i*2)+54);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // Reformat
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync *(model+40) = 0x00;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync for ( i = 39; i > 0; i-- ){
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (*(model+i) == 0x20)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync *(model+i) = 0x00;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync else
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#ifdef VBOXz
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // we don't want any noisy output for now
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync#else /* !VBOX */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync switch (type) {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync int c;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync case DSK_TYPE_ATA:
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf("ata%d %s: ", channel, slave ? " slave" : "master");
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync i=0;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync while(c=*(model+i++))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync printf("%c", c);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync case DSK_TYPE_ATAPI:
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf("ata%d %s: ", channel, slave ? " slave" : "master");
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync i=0;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync while(c=*(model+i++))
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf("%c", c);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (bios_dsk->devices[device].device == DSK_DEVICE_CDROM)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf(" ATAPI-%d CD-ROM/DVD-ROM\n", version);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync else
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf(" ATAPI-%d Device\n", version);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync case DSK_TYPE_UNKNOWN:
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf("ata%d %s: Unknown device\n", channel , slave ? " slave" : "master");
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync#endif /* !VBOX */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // Store the devices counts
a1df400bbe9d64aad400442e56eb637019300a5evboxsync bios_dsk->hdcount = hdcount;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bios_dsk->cdcount = cdcount;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync write_byte(0x40,0x75, hdcount);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync#ifdef VBOX
044af0d1e6474076366759db86f101778c5f20ccvboxsync // we don't want any noisy output for now
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync#else /* !VBOX */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync printf("\n");
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync#endif /* !VBOX */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // FIXME : should use bios=cmos|auto|disable bits
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // FIXME : should know about translation bits
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // FIXME : move hard_drive_post here
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync}
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync// ---------------------------------------------------------------------------
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync// ATA/ATAPI driver : execute a data-out command
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync// ---------------------------------------------------------------------------
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // returns
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 0 : no error
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 1 : BUSY bit set
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 2 : read error
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 3 : expected DRQ=1
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 4 : no sectors left to read/verify
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 5 : more sectors to read/verify
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 6 : no sectors left to write
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // 7 : more sectors to write
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsyncuint16_t ata_cmd_data_out(bio_dsk_t __far *bios_dsk, uint16_t command, uint16_t count)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync{
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint32_t lba;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync char __far *buffer;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t iobase1, iobase2, blksize;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t cylinder;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t head;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t sector;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint16_t device;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint8_t channel, slave;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint8_t status, mode;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync device = bios_dsk->drqp.dev_id;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync channel = device / 2;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync slave = device % 2;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync iobase1 = bios_dsk->channels[channel].iobase1;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync iobase2 = bios_dsk->channels[channel].iobase2;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync mode = bios_dsk->devices[device].mode;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync blksize = 0x200; // was = bios_dsk->devices[device].blksize;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (mode == ATA_MODE_PIO32)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync blksize >>= 2;
044af0d1e6474076366759db86f101778c5f20ccvboxsync else
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync blksize >>= 1;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync status = inb(iobase1 + ATA_CB_STAT);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (status & ATA_CB_STAT_BSY)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // Enable interrupts
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync return 1;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync lba = bios_dsk->drqp.lba;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync buffer = bios_dsk->drqp.buffer;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync sector = bios_dsk->drqp.sector;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync cylinder = bios_dsk->drqp.cylinder;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync head = bios_dsk->drqp.head;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync // sector will be 0 only on lba access. Convert to lba-chs
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (sector == 0) {
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (lba + count >= 268435456)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync sector = (lba & 0xff000000L) >> 24;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync cylinder = 0; /* The parameter lba is just a 32 bit value. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_SN, sector);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_CH, cylinder >> 8);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Leave the bottom 24 bits as is, they are treated correctly by the
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * LBA28 code path. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync lba &= 0xffffff;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync sector = (uint16_t) (lba & 0x000000ffL);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync lba >>= 8;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync cylinder = (uint16_t) (lba & 0x0000ffffL);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync lba >>= 16;
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync head = ((uint16_t) (lba & 0x0000000fL)) | 0x40;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync }
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_FR, 0x00);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_SC, count);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_SN, sector);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync outb(iobase1 + ATA_CB_CH, cylinder >> 8);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (uint8_t) head );
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync outb(iobase1 + ATA_CB_CMD, command);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync while (1) {
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync status = inb(iobase1 + ATA_CB_STAT);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if ( !(status & ATA_CB_STAT_BSY) )
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (status & ATA_CB_STAT_ERR) {
a1df400bbe9d64aad400442e56eb637019300a5evboxsync BX_DEBUG_ATA("%s: write error\n", __func__);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync // Enable interrupts
a1df400bbe9d64aad400442e56eb637019300a5evboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync return 2;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync } else if ( !(status & ATA_CB_STAT_DRQ) ) {
a1df400bbe9d64aad400442e56eb637019300a5evboxsync BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // Enable interrupts
044af0d1e6474076366759db86f101778c5f20ccvboxsync outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync return 3;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync }
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync // FIXME : move seg/off translation here
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync int_enable(); // enable higher priority interrupts
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync while (1) {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync // adjust if there will be an overrun. 2K max sector size
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (FP_OFF(buffer) >= 0xF800)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync buffer = MK_FP(FP_SEG(buffer) + 0x80, FP_OFF(buffer) - 0x800);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
if (mode == ATA_MODE_PIO32) {
buffer = rep_outsd(buffer, blksize, iobase1);
} else {
buffer = rep_outsw(buffer, blksize, iobase1);
}
bios_dsk->drqp.trsfsectors++;
count--;
while (1) {
status = inb(iobase1 + ATA_CB_STAT);
if ( !(status & ATA_CB_STAT_BSY) )
break;
}
if (count == 0) {
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
!= ATA_CB_STAT_RDY ) {
BX_DEBUG_ATA("%s: no sectors left (status %02x)\n", __func__, (unsigned) status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 6;
}
break;
}
else {
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
!= (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
BX_DEBUG_ATA("%s: more sectors left (status %02x)\n", __func__, (unsigned) status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 7;
}
continue;
}
}
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 0;
}
/**
* Read sectors from an attached ATA device.
*
* @returns status code.
* @param bios_dsk Pointer to disk request packet (in the
* EBDA).
*/
int ata_read_sectors(bio_dsk_t __far *bios_dsk)
{
uint16_t n_sect;
int status;
uint8_t device_id;
device_id = bios_dsk->drqp.dev_id;
n_sect = bios_dsk->drqp.nsect;
if (bios_dsk->drqp.sector) {
/* CHS addressing. */
bios_dsk->devices[device_id].blksize = n_sect * 0x200;
status = ata_cmd_data_in(bios_dsk, ATA_CMD_READ_MULTIPLE, n_sect);
bios_dsk->devices[device_id].blksize = 0x200;
} else {
/* LBA addressing. */
if (bios_dsk->drqp.lba + n_sect >= 268435456)
status = ata_cmd_data_in(bios_dsk, ATA_CMD_READ_SECTORS_EXT, n_sect);
else {
bios_dsk->devices[device_id].blksize = n_sect * 0x200;
status = ata_cmd_data_in(bios_dsk, ATA_CMD_READ_MULTIPLE, n_sect);
bios_dsk->devices[device_id].blksize = 0x200;
}
}
return status;
}
/**
* Write sectors to an attached ATA device.
*
* @returns status code.
* @param bios_dsk Pointer to disk request packet (in the
* EBDA).
*/
int ata_write_sectors(bio_dsk_t __far *bios_dsk)
{
uint16_t n_sect;
n_sect = bios_dsk->drqp.nsect;
if (bios_dsk->drqp.sector) {
/* CHS addressing. */
return ata_cmd_data_out(bios_dsk, ATA_CMD_WRITE_SECTORS, n_sect);
} else {
/* LBA addressing. */
if (bios_dsk->drqp.lba + n_sect >= 268435456)
return ata_cmd_data_out(bios_dsk, ATA_CMD_WRITE_SECTORS_EXT, n_sect);
else
return ata_cmd_data_out(bios_dsk, ATA_CMD_WRITE_SECTORS, n_sect);
}
}
// ---------------------------------------------------------------------------
// ATA/ATAPI driver : execute a packet command
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 1 : error in parameters
// 2 : BUSY bit set
// 3 : error
// 4 : not ready
uint16_t ata_cmd_packet(uint16_t device, uint8_t cmdlen, char __far *cmdbuf,
uint16_t header, uint32_t length, uint8_t inout, char __far *buffer)
{
uint16_t iobase1, iobase2;
uint16_t lcount, lbefore, lafter, count;
uint8_t channel, slave;
uint8_t status, mode, lmode;
uint32_t transfer;
bio_dsk_t __far *bios_dsk;
bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
channel = device / 2;
slave = device % 2;
// Data out is not supported yet
if (inout == ATA_DATA_OUT) {
BX_INFO("%s: DATA_OUT not supported yet\n", __func__);
return 1;
}
// The header length must be even
if (header & 1) {
BX_DEBUG_ATA("%s: header must be even (%04x)\n", __func__, header);
return 1;
}
iobase1 = bios_dsk->channels[channel].iobase1;
iobase2 = bios_dsk->channels[channel].iobase2;
mode = bios_dsk->devices[device].mode;
transfer = 0L;
if (cmdlen < 12)
cmdlen = 12;
if (cmdlen > 12)
cmdlen = 16;
cmdlen >>= 1;
// Reset count of transferred data
// @todo: clear in calling code?
bios_dsk->drqp.trsfsectors = 0;
bios_dsk->drqp.trsfbytes = 0;
status = inb(iobase1 + ATA_CB_STAT);
if (status & ATA_CB_STAT_BSY)
return 2;
outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
// outb(iobase1 + ATA_CB_FR, 0x00);
// outb(iobase1 + ATA_CB_SC, 0x00);
// outb(iobase1 + ATA_CB_SN, 0x00);
outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
// Device should ok to receive command
while (1) {
status = inb(iobase1 + ATA_CB_STAT);
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
if (status & ATA_CB_STAT_CHK) {
BX_DEBUG_ATA("%s: error, status is %02x\n", __func__, status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 3;
} else if ( !(status & ATA_CB_STAT_DRQ) ) {
BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 4;
}
int_enable(); // enable higher priority interrupts
// Normalize address
BX_DEBUG_ATA("acp1 buffer ptr: %04x:%04x wlen %04x\n", FP_SEG(cmdbuf), FP_OFF(cmdbuf), cmdlen);
cmdbuf = MK_FP(FP_SEG(cmdbuf) + FP_OFF(cmdbuf) / 16 , FP_OFF(cmdbuf) % 16);
// cmdseg += (cmdoff / 16);
// cmdoff %= 16;
// Send command to device
rep_outsw(cmdbuf, cmdlen, iobase1);
if (inout == ATA_DATA_NO) {
status = inb(iobase1 + ATA_CB_STAT);
}
else {
while (1) {
while (1) {
status = inb(iobase1 + ATA_CB_STAT);
if ( !(status & ATA_CB_STAT_BSY) )
break;
}
// Check if command completed
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 )
break;
if (status & ATA_CB_STAT_CHK) {
BX_DEBUG_ATA("%s: error (status %02x)\n", __func__, status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 3;
}
// Device must be ready to send data
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_CHK) )
!= (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
BX_DEBUG_ATA("%s: not ready (status %02x)\n", __func__, status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 4;
}
// Normalize address
BX_DEBUG_ATA("acp2 buffer ptr: %04x:%04x\n", FP_SEG(buffer), FP_OFF(buffer));
buffer = MK_FP(FP_SEG(buffer) + FP_OFF(buffer) / 16 , FP_OFF(buffer) % 16);
// bufseg += (bufoff / 16);
// bufoff %= 16;
// Get the byte count
lcount = ((uint16_t)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
// adjust to read what we want
if (header>lcount) {
lbefore = lcount;
header -= lcount;
lcount = 0;
}
else {
lbefore = header;
header = 0;
lcount -= lbefore;
}
if (lcount>length) {
lafter = lcount - length;
lcount = length;
length = 0;
}
else {
lafter = 0;
length -= lcount;
}
// Save byte count
count = lcount;
BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
BX_DEBUG_ATA("to 0x%04x:0x%04x\n",FP_SEG(buffer),FP_OFF(buffer));
// If counts not dividable by 4, use 16bits mode
lmode = mode;
if (lbefore & 0x03)
lmode = ATA_MODE_PIO16;
if (lcount & 0x03)
lmode = ATA_MODE_PIO16;
if (lafter & 0x03)
lmode = ATA_MODE_PIO16;
// adds an extra byte if count are odd. before is always even
if (lcount & 0x01) {
lcount += 1;
if ((lafter > 0) && (lafter & 0x01)) {
lafter -= 1;
}
}
if (lmode == ATA_MODE_PIO32) {
lcount >>= 2;
lbefore >>= 2;
lafter >>= 2;
}
else {
lcount >>= 1;
lbefore >>= 1;
lafter >>= 1;
}
if (lmode == ATA_MODE_PIO32) {
if (lbefore)
insd_discard(lbefore, iobase1);
rep_insd(buffer, lcount, iobase1);
if (lafter)
insd_discard(lafter, iobase1);
} else {
if (lbefore)
insw_discard(lbefore, iobase1);
rep_insw(buffer, lcount, iobase1);
if (lafter)
insw_discard(lafter, iobase1);
}
// Compute new buffer address
buffer += count;
// Save transferred bytes count
transfer += count;
bios_dsk->drqp.trsfbytes = transfer;
}
}
// Final check, device must be ready
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_CHK) )
!= ATA_CB_STAT_RDY ) {
BX_DEBUG_ATA("%s: not ready (status %02x)\n", __func__, (unsigned) status);
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 4;
}
// Enable interrupts
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 0;
}
// ---------------------------------------------------------------------------
// ATA/ATAPI driver : reset device; intended for ATAPI devices
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 1 : error
uint16_t ata_soft_reset(uint16_t device)
{
uint16_t iobase1, iobase2;
uint8_t channel, slave;
uint8_t status;
bio_dsk_t __far *bios_dsk;
bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
channel = device / 2;
slave = device % 2;
iobase1 = bios_dsk->channels[channel].iobase1;
iobase2 = bios_dsk->channels[channel].iobase2;
/* Send a reset command to the device. */
outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
outb(iobase1 + ATA_CB_CMD, ATA_CMD_DEVICE_RESET);
/* Wait for the device to clear BSY. */
while (1) {
status = inb(iobase1 + ATA_CB_STAT);
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
/* Final check, device must be ready */
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_CHK) )
!= ATA_CB_STAT_RDY ) {
BX_DEBUG_ATA("%s: not ready (status %02x)\n", __func__, (unsigned) status);
/* Enable interrupts */
outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15);
return 1;
}
/* Enable interrupts */
outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
return 0;
}
// ---------------------------------------------------------------------------
// End of ATA/ATAPI Driver
// ---------------------------------------------------------------------------