/*-
* Copyright (c) 2002-2018 The UbixOS Project.
* All rights reserved.
*
* This was developed by Christopher W. Olsen for the UbixOS Project.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors.
* 2) Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors in the documentation and/or
* other materials provided with the distribution.
* 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <pci/hd.h>
#include <sys/io.h>
#include <sys/device.h>
#include <lib/kmalloc.h>
#include <lib/kprintf.h>
#include <devfs/devfs.h>
#include <string.h>
#include <fs/common/gpt.h>
static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS;
static hdC = 0;
int initHardDisk() {
_initHardDisk( 0xE0 );
_initHardDisk( 0xF0 );
}
int _initHardDisk( int hdD ) {
int i = 0x0;
int x = 0x0;
int minor = 0x0;
struct device_interface *devInfo = 0x0;
struct device_interface *devInfo2 = 0x0;
struct dos_partition *d = 0x0;
struct driveInfo *hdd = 0x0;
struct driveInfo *hdd2 = 0x0;
char *data = 0x0;
char *data2 = 0x0;
char name[16];
struct bsd_disklabel *bsdd = 0x0;
//GPT
char *secbuf = 0x0;
// Allocate memory for hdd structure
hdd = ( struct driveInfo * ) kmalloc( sizeof( struct driveInfo ) );
hdd->ata_identify = ( struct ata_identify_data * ) kmalloc( sizeof( struct ata_identify_data ) );
hdd->hdPort = 0x1F0;
hdd->hdDev = hdD; //0x40;
hdd->parOffset = 0x0;
hdd->part = 0x2;
/* Allocate memory for device structure and set it up correctly */
devInfo = ( struct device_interface * ) kmalloc( sizeof( struct device_interface ) );
devInfo->read = ( void * ) &hdRead;
devInfo->write = ( void * ) &hdWrite;
devInfo->reset = ( void * ) &hdReset;
devInfo->init = ( void * ) &hdInit;
devInfo->ioctl = ( void * ) &hdIoctl;
devInfo->stop = ( void * ) &hdStop;
devInfo->start = ( void * ) &hdStart;
devInfo->standby = ( void * ) &hdStandby;
devInfo->info = hdd;
devInfo->major = hdC + 0x1;
data = ( char * ) kmalloc( 512 );
d = ( struct dos_partition * ) ( data + 0x1BE );
data2 = ( char * ) kmalloc( 512 );
bsdd = ( struct bsd_disklabel * ) data2;
if( device_add( 0, 'c', devInfo ) == 0x0 ) {
kprintf( "ad%i - Start: [0x0], Size: [0x%x/0x%X]\n", hdC, hdd->hdSize, hdd->hdSize * 512 );
bzero( &name, 16 );
sprintf( name, "ad%ip%i", hdC, hdd->part );
devfs_makeNode( name, 'b', 0x1, 0x0 );
hdRead( devInfo->info, data, 0x0, 0x1 );
if( d[0].dp_type == 0xEE ) {
secbuf = ( char * ) kmalloc( 65536 );
if( gptread( &freebsd_ufs_uuid, devInfo, secbuf ) == -1 ) {
kprintf("%s: unable to load GPT\n", "KERNEL");
//return (-1);
} else {
devInfo2 = ( struct device_interface * ) kmalloc( sizeof( struct device_interface ) );
hdd2 = ( struct driveInfo * ) kmalloc( sizeof( struct driveInfo ) );
memcpy( devInfo2, devInfo, sizeof( struct device_interface ) );
memcpy( hdd2, hdd, sizeof( struct driveInfo ) );
//hdd2->parOffset = d[i].dp_start;
devInfo2->info = hdd2;
minor++;
if( gptfind( &freebsd_ufs_uuid, devInfo2, hdd->part ) == -1 ) {
//MrOlsen (2016-01-11) FIX: I am using "1" as partition 1
kprintf("%s: no UFS partition was found\n", "KERNEL");
//return (-1);
}
//MrOlsen (2016-01-14) DEBUG: This was just debugging code
//kprintf("[%i - %i]\n", hdd->parOffset, hdd2->parOffset);
if( device_add( minor, 'c', devInfo2 ) == 0x0 ) {
bzero( &name, 16 );
sprintf( name, "ad%ip%i", hdC, hdd->part );
kprintf( "%s - Type: [0x%X - %s], Start: [%i], Offset: [%i], Size: [%i], MM: [%i:%i]\n", name, d[0].dp_type, (d[0].dp_type >= 0 && d[0].dp_type <= 255) ? part_types[d[0].dp_type] : "Unknown", hdd2->lba_start, hdd2->parOffset, hdd2->lba_end - hdd2->lba_start, devInfo->major, minor );
devfs_makeNode( name, 'c', 0x1, minor );
}
}
} else {
for( i = 0x0; i < 0x4; i++ ) {
if( d[i].dp_type == 0xEE )
kprintf( "This is a GPT partitioned device.\n" );
if( d[i].dp_type != 0x0 ) {
devInfo2 = ( struct device_interface * ) kmalloc( sizeof( struct device_interface ) );
hdd2 = ( struct driveInfo * ) kmalloc( sizeof( struct driveInfo ) );
memcpy( devInfo2, devInfo, sizeof( struct device_interface ) );
memcpy( hdd2, hdd, sizeof( struct driveInfo ) );
hdd2->parOffset = d[i].dp_start;
devInfo2->info = hdd2;
minor++;
if( device_add( minor, 'c', devInfo2 ) == 0x0 ) {
bzero( &name, 16 );
sprintf( name, "ad%is%i", hdC, i + 1 );
kprintf( "%s - Type: [0x%X - %s], Start: [0x%X], Size: [0x%X], MM: [%i:%i]\n", name, d[i].dp_type, (d[i].dp_type >= 0 && d[i].dp_type <= 255) ? part_types[d[i].dp_type] : "Unknown", d[i].dp_start, d[i].dp_size, devInfo->major, minor );
devfs_makeNode( name, 'c', 0x1, minor );
if( d[i].dp_type == 0xA5 ) {
// XXX - Why do i need to add 1?
hdRead( devInfo->info, data2, d[i].dp_start + 1, 0x1 );
for( x = 0; x < bsdd->d_npartitions; x++ ) {
if( bsdd->d_partitions[x].p_size > 0 ) {
bzero( &name, 16 );
sprintf( name, "ad%is%i%c", hdC, i + 1, 'a' + x );
//New Nodes
devInfo2 = ( struct device_interface * ) kmalloc( sizeof( struct device_interface ) );
hdd2 = ( struct driveInfo * ) kmalloc( sizeof( struct driveInfo ) );
memcpy( devInfo2, devInfo, sizeof(struct device_interface ) );
memcpy( hdd2, hdd, sizeof( struct driveInfo ) );
//hdd2->parOffset = d[i].dp_start + bsdd->d_partitions[x].p_offset;
hdd2->lba_start = d[i].dp_start;
hdd2->parOffset = bsdd->d_partitions[x].p_offset;
devInfo2->info = hdd2;
minor++;
device_add( minor, 'c', devInfo2 );
devfs_makeNode( name, 'c', 0x1, minor );
kprintf( "%s - Type: [%s], Start: [0x%X], Size: [0x%X], MM: [%i:%i]\n", name, fstypenames[bsdd->d_partitions[x].p_fstype], bsdd->d_partitions[x].p_offset, bsdd->d_partitions[x].p_size, devInfo->major, minor );
}
}
}
}
}
}
}
}
kfree( data );
hdC++;
return ( 0x0 );
}
int hdStandby() {
/* Not Implemented */
return ( 0x0 );
}
int hdStart() {
/* Not Implemented */
return ( 0x0 );
}
int hdStop() {
/* Not Implemented */
return ( 0x0 );
}
int hdIoctl() {
/* Not Implemented */
return ( 0x0 );
}
int hdReset() {
/* Not Implemented */
return ( 0x0 );
}
int hdInit( struct device_node *dev ) {
u_int8_t retVal = 0x0;
int counter = 0x0;
u_int16_t *tmp = 0x0;
struct driveInfo *hdd = dev->devInfo->info;
for( counter = 1000000; counter >= 0; counter-- ) {
retVal = inportByte( hdd->hdPort + ATA_COMMAND ) & ATA_S_BUSY;
if( !retVal ) {
goto ready;
}
}
kprintf( "Error Initializing Drive\n" );
return( 1 );
ready:
outportByte( hdd->hdPort + ATA_DRIVE, hdd->hdDev );
outportByte( hdd->hdPort + ATA_COMMAND, ATA_IDENTIFY );
//for (counter = 1000000; counter >= 0; counter--) {
for( counter = 10000000; counter >= 0; counter-- ) {
retVal = inportByte( hdd->hdPort + ATA_COMMAND );
if( ( retVal & 1 ) != 0x0 ) {
kprintf( "Error Drive Not Available\n" );
return( 1 );
}
if( ( retVal & 8 ) != 0x0 ) {
goto go;
}
}
kprintf( "Time Out Waiting On Drive\n" );
return( 1 );
go:
tmp = ( u_int16_t * ) hdd->ata_identify;
for( counter = 0; counter < 256; counter++ ) {
tmp[counter] = inportWord( hdd->hdPort + ATA_DATA );
}
retVal = tmp[0x2F] & 0xFF;
switch( retVal ) {
case 0:
hdd->hdShift = 0;
hdd->hdMulti = 1;
break;
case 2:
hdd->hdShift = 1;
hdd->hdMulti = retVal;
break;
case 4:
hdd->hdShift = 2;
hdd->hdMulti = retVal;
break;
case 8:
hdd->hdShift = 3;
hdd->hdMulti = retVal;
break;
case 16:
hdd->hdShift = 4;
hdd->hdMulti = retVal;
break;
case 32:
hdd->hdShift = 5;
hdd->hdMulti = retVal;
break;
case 64:
hdd->hdShift = 6;
hdd->hdMulti = retVal;
break;
case 128:
hdd->hdShift = 7;
hdd->hdMulti= retVal;
break;
default:
kprintf( "Error BLOCK Mode Unavailable: [%x]\n", retVal );
return (1);
}
if( hdd->ata_identify->command_set_enabled1 & ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE ) {
hdd->lba_high = hdd->ata_identify->max_48bit_lba[7] << 24;
hdd->lba_high |= hdd->ata_identify->max_48bit_lba[6] << 16;
hdd->lba_high |= hdd->ata_identify->max_48bit_lba[5] << 8;
hdd->lba_high |= hdd->ata_identify->max_48bit_lba[4];
hdd->lba_low = hdd->ata_identify->max_48bit_lba[3] << 24;
hdd->lba_low |= hdd->ata_identify->max_48bit_lba[2] << 16;
hdd->lba_low |= hdd->ata_identify->max_48bit_lba[1] << 8;
hdd->lba_low |= hdd->ata_identify->max_48bit_lba[0];
} else {
hdd->lba_high = 0;
hdd->lba_low = hdd->ata_identify->total_num_sectors[3] << 24;
hdd->lba_low |= hdd->ata_identify->total_num_sectors[2] << 16;
hdd->lba_low |= hdd->ata_identify->total_num_sectors[1] << 8;
hdd->lba_low |= hdd->ata_identify->total_num_sectors[0];
}
// If the ATA device reports its sector size (bit 12 of Word 106), then use that instead.
if( hdd->ata_identify->physical_logical_sector_info & ATA_IDENTIFY_SECTOR_LARGER_THEN_512_ENABLE ) {
hdd->sector_size = hdd->ata_identify->words_per_logical_sector[3] << 24;
hdd->sector_size |= hdd->ata_identify->words_per_logical_sector[2] << 16;
hdd->sector_size |= hdd->ata_identify->words_per_logical_sector[1] << 8;
hdd->sector_size |= hdd->ata_identify->words_per_logical_sector[0];
} else {
// Default the sector size to 512 bytes
hdd->sector_size = 512;
}
kprintf( "LBA [0x%X - 0x%X], LBA_HIGH: %i, LBA_LOW: %i, SECTOR_SIZE: %i\n", hdd->ata_identify->command_set_enabled1, hdd->ata_identify->command_set_enabled1 & ATA_IDENTIFY_COMMAND_SET_SUPPORTED1_48BIT_ENABLE, hdd->lba_high, hdd->lba_low, hdd->sector_size );
outportByte( hdd->hdPort + hdSecCount, retVal );
outportByte( hdd->hdPort + hdHead, hdd->hdDev );
outportByte( hdd->hdPort + hdCmd, 0xC6 );
hdd->hdMask = retVal;
//hdd->hdSize = (hdd->hdSector[0x7B] * 256 * 256 * 256) + (hdd->hdSector[0x7A] * 256 * 256) + (hdd->hdSector[0x79] * 256) + hdd->hdSector[0x78];
// MrOlsen (2016-01-11) NOTE: Must phase out hdSize
hdd->hdSize = hdd->lba_low + hdd->lba_high;
hdd->hdEnable = 1;
kprintf( "Drive: [0x%X/0x%X], Size: [%i Sectors/%i MB]\n", hdd->hdPort, hdd->hdDev, hdd->hdSize, hdd->hdSize / 2048 );
dev->devInfo->size = hdd->hdSize * 512;
dev->devInfo->initialized = 0x1;
return (0x0);
}
int hdWrite(struct driveInfo *hdd, void *baseAddr, uInt32 startSector, uInt32 sectorCount) {
long counter = 0x0;
long retVal = 0x0;
short transactionCount = 0x0;
short *tmp = (short *) baseAddr;
if (hdd->lba_start == 0)
startSector += hdd->parOffset;
else
startSector += hdd->lba_start;
if (hdd->hdEnable == 0x0) {
kprintf("Invalid Drive\n");
return (1);
}
if ((sectorCount >> hdd->hdShift) == 0x0) {
hdd->hdCalc = sectorCount; /* hdd->hdMask; */
transactionCount = 1;
}
else {
hdd->hdCalc = hdd->hdMulti;
transactionCount = sectorCount >> hdd->hdShift;
}
for (; transactionCount > 0; transactionCount--) {
//for (counter = 1000000; counter >= 0; counter--) {
for (counter = 10000000; counter >= 0; counter--) {
retVal = inportByte(hdd->hdPort + hdStat) & 0x80;
if (!retVal)
goto ready;
}
kprintf("Time Out Waiting On Drive\n");
return (1);
ready: outportByte(hdd->hdPort + hdSecCount, hdd->hdCalc);
outportByte(hdd->hdPort + hdSecNum, (startSector & 0xFF));
retVal = startSector >> 8;
outportByte(hdd->hdPort + hdCylLow, (retVal & 0xFF));
retVal >>= 8;
outportByte(hdd->hdPort + hdCylHi, (retVal & 0xFF));
retVal >>= 8;
retVal &= 0x0F;
retVal |= (hdd->hdDev | 0xA0); //Test As Per TJ
outportByte(hdd->hdPort + hdHead, (retVal & 0xFF));
if (hdd->hdShift > 0)
outportByte(hdd->hdPort + hdCmd, 0xC5);
else
outportByte(hdd->hdPort + hdCmd, 0x30);
//for (counter = 1000000; counter >= 0; counter--) {
for (counter = 10000000; counter >= 0; counter--) {
retVal = inportByte(hdd->hdPort + hdStat);
if ((retVal & 1) != 0x0) {
kprintf("HD Write Error\n");
return (1);
}
if ((retVal & 8) != 0x0) {
goto go;
}
}
kprintf("Time Out Waiting On Drive\n");
return (1);
go: for (counter = 0; counter < (hdd->hdCalc << 8); counter++) {
outportWord(hdd->hdPort + hdData, (short) tmp[counter]);
}
tmp += (counter + 0);
startSector += hdd->hdCalc;
}
return (0);
}
int hdRead(struct driveInfo *hdd, void *baseAddr, uInt32 startSector, uInt32 sectorCount) {
long counter = 0x0;
long retVal = 0x0;
short transactionCount = 0x0;
short *tmp = (short *) baseAddr;
startSector += hdd->parOffset;
startSector += hdd->lba_start;
if (hdd->hdEnable == 0x0) {
kprintf("Invalid Drive\n");
return (1);
}
if ((sectorCount >> hdd->hdShift) == 0x0) {
hdd->hdCalc = sectorCount; /* hdd->hdMask); */
transactionCount = 1;
}
else {
hdd->hdCalc = hdd->hdMulti;
transactionCount = sectorCount >> hdd->hdShift;
}
for (; transactionCount > 0; transactionCount--) {
//for (counter = 1000000; counter >= 0; counter--) {
for (counter = 10000000; counter >= 0; counter--) {
retVal = inportByte(hdd->hdPort + hdStat) & 0x80;
if (!retVal)
goto ready;
}
kprintf("Time Out Waiting On Drive\n");
return (1);
ready: outportByte(hdd->hdPort + hdSecCount, hdd->hdCalc);
outportByte(hdd->hdPort + hdSecNum, (startSector & 0xFF));
retVal = startSector >> 8;
outportByte(hdd->hdPort + hdCylLow, (retVal & 0xFF));
retVal >>= 8;
outportByte(hdd->hdPort + hdCylHi, (retVal & 0xFF));
retVal >>= 8;
retVal &= 0x0F;
retVal |= (hdd->hdDev | 0xA0); //Test as per TJ
//retVal |= hdd->hdDev; //retVal |= (hdd->hdDev | 0xA0); //Test as per TJ
outportByte(hdd->hdPort + hdHead, (retVal & 0xFF));
if (hdd->hdShift > 0)
outportByte(hdd->hdPort + hdCmd, 0xC4);
else
outportByte(hdd->hdPort + hdCmd, 0x20);
//for (counter = 1000000; counter >= 0; counter--) {
for (counter = 10000000; counter >= 0; counter--) {
retVal = inportByte(hdd->hdPort + hdStat);
if ((retVal & 1) != 0x0) {
kprintf("HD Read Error: [%i:0x%X:%i]\n", counter, (uInt32) baseAddr, startSector);
return (1);
}
if ((retVal & 8) != 0x0) {
goto go;
}
}
kprintf("Error: Time Out Waiting On Drive\n");
return (1);
go: for (counter = 0; counter < (hdd->hdCalc << 8); counter++) {
tmp[counter] = inportWord(hdd->hdPort + hdData);
//kprintf("[0x%X]", tmp[counter]);
}
tmp += (counter + 0);
startSector += hdd->hdCalc;
}
return (0);
}
/***
$Log: hd.c,v $
Revision 1.5 2006/10/12 15:00:26 reddawg
More changes
Revision 1.4 2006/10/10 14:14:01 reddawg
UFS Reading
Revision 1.3 2006/10/09 02:58:05 reddawg
Fixing UFS
Revision 1.2 2006/10/06 15:48:01 reddawg
Starting to make ubixos work with UFS2
Revision 1.1.1.1 2006/06/01 12:46:16 reddawg
ubix2
Revision 1.2 2005/10/12 00:13:37 reddawg
Removed
Revision 1.1.1.1 2005/09/26 17:24:34 reddawg
no message
Revision 1.16 2004/08/26 22:51:19 reddawg
TCA touched me :( i think he likes men....
sched.h: kTask_t added parentPid
endtask.c: fixed term back to parentPid
exec.c: cleaned warnings
fork.c: fixed term to childPid
sched.c: clean up for dead tasks
systemtask.c: clean up dead tasks
kmalloc.c: cleaned up warnings
udp.c: cleaned up warnings
bot.c: cleaned up warnings
shell.c: cleaned up warnings
tcpdump.c: took a dump
hd.c: cleaned up warnings
ubixfs.c: stopped prning debug info
Revision 1.15 2004/08/15 00:33:02 reddawg
Wow the ide driver works again
Revision 1.14 2004/08/14 21:56:44 reddawg
Added initialized byte to the device system to make it easy to add child devices which use parent hardware.
Revision 1.13 2004/08/02 11:43:17 reddawg
Fixens
Revision 1.12 2004/07/21 10:02:09 reddawg
devfs: renamed functions
device system: renamed functions
fdc: fixed a few potential bugs and cleaned up some unused variables
strol: fixed definition
endtask: made it print out freepage debug info
kmalloc: fixed a huge memory leak we had some unhandled descriptor insertion so some descriptors were lost
ld: fixed a pointer conversion
file: cleaned up a few unused variables
sched: broke task deletion
kprintf: fixed ogPrintf definition
Revision 1.11 2004/05/19 23:36:52 reddawg
Bug Fixes
Revision 1.10 2004/05/19 15:20:06 reddawg
Fixed reference problems due to changes in drive subsystem
Revision 1.9 2004/05/19 15:07:59 reddawg
Typo defInfo should of been devInfo
Revision 1.7 2004/05/19 04:07:43 reddawg
kmalloc(size,pid) no more it is no kmalloc(size); the way it should of been
Revision 1.6 2004/04/28 21:10:40 reddawg
Lots Of changes to make it work with existing os
Revision 1.5 2004/04/28 02:37:34 reddawg
More updates for using the new driver subsystem
Revision 1.4 2004/04/28 02:22:54 reddawg
This is a fiarly large commit but we are starting to use new driver model
all around
Revision 1.3 2004/04/27 21:05:19 reddawg
Updating drivers to use new model
Revision 1.2 2004/04/26 22:22:33 reddawg
DevFS now uses correct size of device
Revision 1.1.1.1 2004/04/15 12:07:16 reddawg
UbixOS v1.0
Revision 1.12 2004/04/13 16:36:33 reddawg
Changed our copyright, it is all now under a BSD-Style license
END
***/