/*- * 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 ***/