head 4.4; access ; symbols ; locks oasisa:4.4; strict; comment @ * @; 4.4 date 2001.06.19.12.13.12; author oasisa; state Exp; branches ; next ; desc @New Repository; 6/19/2001 (klh) @ 4.4 log @New Repository; 6/19/2001 (klh) @ text @/****************************************************************************/ /* Copyright 1994 MBARI */ /****************************************************************************/ /* $Header: disk.c,v 1.1 2001/06/19 11:42:56 oasisa Exp $ */ /* Summary : IDE Disk Driver for OASIS Mooring Controller */ /* Filename : disk.c */ /* Author : Robert Herlien (rah) */ /* Project : OASIS Mooring */ /* $Revision: 1.1 $ */ /* Created : 12/17/94 */ /* */ /* MBARI provides this documentation and code "as is", with no warranty, */ /* express or implied, of its quality or consistency. It is provided without*/ /* support and without obligation on the part of the Monterey Bay Aquarium */ /* Research Institute to assist in its use, correction, modification, or */ /* enhancement. This information should not be published or distributed to */ /* third parties without specific written permission from MBARI. */ /* */ /****************************************************************************/ /* Modification History: */ /* 17dec94 rah - created */ /* $Log: disk.c,v $ * Revision 1.1 2001/06/19 11:42:56 11:42:56 oasisa (Oasis users) * Initial revision * * Revision 3.9 97/10/28 14:00:00 14:00:00 bobh (Bob Herlien) * EqPac Deployment of Nov 1997 * * Revision 3.6 96/10/30 14:00:28 14:00:28 bobh (Bob Herlien) * Release for EqPac, M2 Test Replacement * * Revision 3.4 96/06/18 15:24:40 15:24:40 bobh (Bob Herlien) * June '96 deployment of M1 * * Revision 3.3 95/04/13 13:47:08 13:47:08 hebo (Bob Herlien) * Drifter Deployment for Coop (flip) cruise * * Revision 3.0 95/02/21 18:42:55 18:42:55 hebo (Bob Herlien) * February '95 Deployment * */ /****************************************************************************/ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* DISK definition */ #include /* Log record definitions */ #include /* OASIS I/O definitions */ #include /* Kittyhawk IDE drive definitions */ #include /* OASIS task dispatcher */ #ifdef DISK /* Include remainder only if DISK */ typedef enum /************************************/ { /* Type for diskOnState */ DISK_OFF = 0, /* Disk is turned off */ DISK_SPINNING, /* Disk is spinning but not in use */ DISK_IN_USE /* Disk is being used */ } DiskState; /************************************/ /********************************/ /* External Data */ /********************************/ Extern Reg Word error; /* Error vector */ Extern Reg TimeOfDay tod; /* Current time in TimeOfDay format */ /********************************/ /* External Functions */ /********************************/ Extern Void bankCopy( Nat16 bank, Byte *dst_addr, const Byte *src_addr, Nat16 len ); Extern Driver *drvr_find( char *name ); /********************************/ /* Global Data */ /********************************/ Global LogBlk dskBlksWritten; /* Nmbr blks attempted write to disk*/ Global Nat16 dskBlkErrors; /* Nmbr of above blks with errors */ /********************************/ /* Module Local Data */ /********************************/ MLocal Errno diskInitStatus; /* Disk Init status */ MLocal Nat16 diskBlocks; /* Disk capacity in blocks */ MLocal Nat16 diskCylinders, diskHeads; MLocal Nat16 diskSectorsPerTrack, diskSectorsPerCylinder; MLocal Semaphore diskSem; /* Mutex sem for disk I/O */ MLocal Reg DiskState diskOnState; /* State of disk use */ /************************************************************************/ /* Function : diskInit */ /* Purpose : Initialize this module */ /* Inputs : None */ /* Outputs : OK */ /************************************************************************/ Void diskInit( Void ) { sem_init( &diskSem, 1 ); /* Init the disk semaphore */ diskOnState = DISK_OFF; /* Show disk is off */ } /* diskInit() */ /************************************************************************/ /* Function : diskColdInit */ /* Purpose : Initialize this module */ /* Inputs : None */ /* Outputs : None */ /************************************************************************/ Void diskColdInit( Void ) { diskInitStatus = DSK_NOT_INIT; /* Just show disk not init'd */ diskOnState = DISK_OFF; /* Show disk is off */ dskBlksWritten = 0; /* Show no disk data written */ dskBlkErrors = 0; /* Show no disk errors */ /* Can't actually init, because this function */ /*is called before task dispatcher is initialized*/ } /* diskColdInit() */ /************************************************************************/ /* Function : waitDiskStatus */ /* Purpose : Wait for bit in disk alternate status register */ /* Inputs : Number of seconds to wait, bit to wait for */ /* Outputs : OK or DSK_BUSY */ /* Comment : Also checks BUSY bit, which must be off */ /************************************************************************/ Errno waitDiskStatus( Nat16 delay, Nat16 waitBit ) { Nat16 i; for ( i = delay * TICKS_PER_SECOND; i; i-- ) { if ( (disk_alt_status() & (BUSY_BIT | waitBit)) == waitBit ) return( OK ); /* Check busy & passed bits*/ task_delay( 1 ); /* If not OK, wait */ } return( DSK_BUSY ); /* Timed out */ } /* waitDiskStatus() */ /************************************************************************/ /* Function : waitDiskBusy */ /* Purpose : Wait for disk to become not busy */ /* Inputs : Number of seconds to wait */ /* Outputs : OK or DSK_BUSY */ /************************************************************************/ Errno waitDiskBusy( Nat16 delay ) { return( waitDiskStatus(delay, 0) ); } /* waitDiskBusy() */ /************************************************************************/ /* Function : waitDiskReady */ /* Purpose : Wait for disk to become ready */ /* Inputs : Number of seconds to wait */ /* Outputs : OK or DSK_NOT_READY */ /************************************************************************/ Errno waitDiskReady( Nat16 delay ) { return ( (waitDiskStatus(delay, READY_BIT) == OK) ? OK : DSK_NOT_READY ); } /* waitDiskReady() */ /************************************************************************/ /* Function : waitDiskDRQ */ /* Purpose : Wait for disk to assert DRQ (Data Request) */ /* Inputs : Number of seconds to wait */ /* Outputs : OK or DSK_NO_DRQ */ /************************************************************************/ Errno waitDiskDRQ( Nat16 delay ) { return ( (waitDiskStatus(delay, DRQ_BIT) == OK) ? OK : DSK_NO_DRQ ); } /* waitDiskDRQ() */ /************************************************************************/ /* Function : diskOn */ /* Purpose : Turn disk drive on */ /* Inputs : None */ /* Outputs : OK, DSK_BUSY, or disStatus */ /************************************************************************/ Errno diskOn( Void ) { if ( diskOnState != DISK_OFF ) /* If disk already on, */ { diskOnState = DISK_IN_USE; /* Show we're using it and return*/ return( OK ); } piab_ddrc = (Byte)0xff; /* Port C is output port */ piab_pdc = DSK_PWRON; /* Turn on disk drive */ task_delay( TICKS_PER_SECOND ); /* Wait for disk to power up */ piab_ddra = 0; /* Ports A, B are inputs */ piab_ddrb = 0; diskOnState = DISK_IN_USE; /* Show we're using disk */ return(waitDiskBusy(DISK_TIMEOUT)); /* Wait for disk not busy */ } /* diskOn() */ /************************************************************************/ /* Function : diskOff */ /* Purpose : Turn off disk drive */ /* Inputs : None */ /* Outputs : None */ /************************************************************************/ Void diskOff( Void ) { disk_write_port(DSK_SECT_CNT, 1); /* 5 second timeout */ disk_command( STANDBY_1 ); /* Put disk on standby */ disk_command( STANDBY_2 ); waitDiskBusy(DISK_STDBY_TIMEOUT); /* Wait for disk to go to standby*/ disk_command( SLEEP_1 ); /* Put disk to sleep */ disk_command( SLEEP_2 ); task_delay( TICKS_PER_SECOND ); /* Wait one second */ piab_ddra = (Byte)0xff; /* Ports A, B, C all outputs */ piab_ddrb = (Byte)0xff; piab_ddrc = (Byte)0xff; piab_pda = 0; /* Keep all disk I/O bits at gnd*/ piab_pdb = 0; piab_pdc = DSK_PWROFF; /* Turn off disk */ diskOnState = DISK_OFF; /* Show it's off */ } /* diskOff() */ /************************************************************************/ /* Function : disk_drv */ /* Purpose : Task to turn off disk drive when appropriate */ /* Inputs : Driver pointer */ /* Outputs : None */ /************************************************************************/ Void disk_drv( Driver *dp ) { while ( diskOnState == DISK_IN_USE ) /* Check if disk in use */ delay_secs( dp->drv_parms[TIMEOUT] ); /* If so, wait another timeout*/ sem_take( &diskSem ); /* Mutex on disk I/O */ if ( diskOnState == DISK_SPINNING ) diskOff(); /* Turn off disk */ sem_give( &diskSem ); /* Release mutex sem */ } /* disk_drv() */ /************************************************************************/ /* Function : checkDiskOff */ /* Purpose : Schedule disk drive off */ /* Inputs : None */ /* Outputs : None */ /************************************************************************/ Void checkDiskOff( Void ) { Reg Driver *dp; if ( (dp = drvr_find("disk")) == DRV_NULL ) /* Find disk drvr. */ diskOff(); /* If none, turn off now*/ else { /* If found, show done */ diskOnState = DISK_SPINNING; dp->drv_wakeup = tod + dp->drv_parms[TIMEOUT]; dp->drv_flags |= DO_SYNC; } /* and run drvr after tmout*/ sem_give( &diskSem ); /* Release mutex sem */ } /* checkDiskOff() */ /************************************************************************/ /* Function : resetDisk */ /* Purpose : Wait for disk to become ready */ /* Inputs : None */ /* Outputs : OK or DSK_BUSY */ /************************************************************************/ Errno resetDisk( Void ) { disk_write_port( DSK_CONTROL, CONTROL_RESET ); /* Reset drive */ disk_write_port( DSK_CONTROL, CONTROL_NORMAL ); /* Turn off reset*/ return( waitDiskBusy(DISK_TIMEOUT) ); /* Check OK */ } /* resetDisk() */ /************************************************************************/ /* Function : diskRetry */ /* Purpose : Perform a disk function with retry */ /* Inputs : Function to perform, memory bank and address for function*/ /* Outputs : Disk Error number */ /************************************************************************/ Errno diskRetry( Errno (*diskFunc)(), Nat16 drvbank, Byte *drvbuf ) { if ( (*diskFunc)(drvbank, drvbuf) == OK ) return( OK ); if ( resetDisk() != OK ) return( DSK_BUSY ); return( (*diskFunc)(drvbank, drvbuf) ); } /* diskRetry() */ /************************************************************************/ /* Function : identifyDrive */ /* Purpose : Get Identify Drive buffer */ /* Inputs : Bank and buffer to put drive parameters in */ /* Outputs : OK or Error number */ /************************************************************************/ Errno identifyDrive( Nat16 drvbank, Byte *drvbuf ) { if ( waitDiskReady(DISK_ID_TIMEOUT) != OK ) /* Wait for disk ready */ return( DSK_NOT_READY ); disk_command( IDENTIFY_DRIVE ); /* Ask for disk ID buffer*/ if ( waitDiskDRQ(DISK_ID_TIMEOUT) != OK ) /* Wait for Data request */ return( DSK_NO_DRQ ); disk_read_buffer( drvbank, drvbuf ); /* Read the ID buffer */ if ( disk_status() & ERROR_BIT ) /* Check for errors */ return( disk_error() ); return( OK ); } /* identifyDrive() */ /************************************************************************/ /* Function : checkDiskInitAndOn */ /* Purpose : Check that disk has been initialized, and turn it on */ /* Inputs : None */ /* Outputs : OK, or ERROR if can't turn on or initialize hard disk */ /************************************************************************/ Errno checkDiskInitAndOn( Void ) { Reg Nat32 totalSectors; Reg Nat16 *idbuf; sem_take( &diskSem ); /* Mutex on disk I/O */ /* released at checkDiskOff*/ if ( diskOn() != OK ) /* Turn on the drive */ return( DSK_BUSY ); /* If busy, return error*/ disk_write_port( DSK_CONTROL, CONTROL_NORMAL ); /* Set enbl, no int */ disk_write_port( DSK_DRV_HEAD, DRIVE_BYTE ); /* Specify disk 0 */ if ( diskInitStatus == OK ) /* If disk has been init'd*/ return( OK ); /* OK, just return */ /* If not yet init, or tried and failed */ /* try the init (identifyDrive) again */ diskInitStatus = diskRetry( identifyDrive, 0, (Byte *)RW_BUFFER ); /* Get drive parameters */ if ( diskInitStatus != OK ) /* If failed, return */ return( diskInitStatus ); idbuf = (Nat16 *)RW_BUFFER; /* Got ID into RW buffer*/ diskCylinders = idbuf[1]; /* If OK, calculate disk*/ diskHeads = idbuf[3]; /* size */ diskSectorsPerTrack = idbuf[6]; diskSectorsPerCylinder = diskSectorsPerTrack * diskHeads; totalSectors = ((diskSectorsPerCylinder) * (Nat32)diskCylinders); if ( totalSectors < (2 * SECTORS_PER_BLK) ) /* If < 2 blocks, parameters*/ diskInitStatus = DSK_BAD_PARMS; /* must be wrong */ diskBlocks = (totalSectors - SECTOR_OFFSET) >> BLK_TO_SECT_SHFT; return( diskInitStatus ); } /* checkDiskInitAndOn() */ /************************************************************************/ /* Function : diskReadSector */ /* Purpose : Read one disk sector into banked memory */ /* Inputs : Bank and buffer to read sector into */ /* Outputs : OK or disk error code */ /* Comment : Assumes cylinder, head, and sector have all been set up*/ /************************************************************************/ Errno diskReadSector( Nat16 bank, Byte *sectBuff ) { if ( waitDiskReady(DISK_TIMEOUT) != OK ) /* Wait for disk ready */ return( DSK_NOT_READY ); disk_write_port( DSK_SECT_CNT, 1 ); /* Do one sector */ disk_command( READ_SECTOR ); /* Initiate disk read */ if ( waitDiskDRQ(DISK_DRQ_TIMEOUT) != OK ) /* Wait for Data request*/ return( DSK_NO_DRQ ); disk_read_buffer( bank, sectBuff ); /* Read the disk buffer */ if ( disk_status() & ERROR_BIT ) /* Check for errors */ return( disk_error() ); return( OK ); } /* diskReadSector() */ /************************************************************************/ /* Function : diskWriteSector */ /* Purpose : Write one disk sector from banked memory */ /* Inputs : Bank and buffer to write sector from */ /* Outputs : OK or disk error code */ /* Comment : Assumes cylinder, head, and sector have all been set up*/ /************************************************************************/ Errno diskWriteSector( Nat16 bank, Byte *sectBuff ) { if ( waitDiskReady(DISK_TIMEOUT) != OK ) /* Wait for disk ready */ return( DSK_NOT_READY ); disk_write_port( DSK_SECT_CNT, 1 ); /* Do one sector */ disk_command( WRITE_SECTOR ); /* Initiate disk write */ if ( waitDiskDRQ(DISK_DRQ_TIMEOUT) != OK ) /* Wait for Data request*/ return( DSK_NO_DRQ ); disk_write_buffer( bank, sectBuff ); /* Write the disk buffer*/ if ( waitDiskBusy(DISK_TIMEOUT) != OK ) /* Wait for the write to*/ return( DSK_BUSY ); /* complete */ if ( disk_status() & (ERROR_BIT | WRITE_FAULT_BIT) ) return( disk_error() ); /* Check for errors */ return( OK ); } /* diskWriteSector() */ /************************************************************************/ /* Function : doDiskBlk */ /* Purpose : Perform disk function on every sector for one disk block*/ /* Inputs : Function to perform (read or write), Disk block number,*/ /* memory block number */ /* Outputs : OK or disk error code */ /************************************************************************/ Errno doDiskBlk( Errno (*dskSectorFunc)(), LogBlk dskblk, LogBlk memblk ) { Nat16 sector; /* Sector nmbr from blk beginning */ Reg Errno rtn; /* Return code from diskSectorFunc*/ Reg LogAddr addr; /* Block address for sector I/O */ Reg Nat32 logSectNum; /* Logical sector nmbr (0-enddisk)*/ Reg Nat16 cylinder, rem; /* Cylinder number, remainder */ for ( sector = 0; sector < SECTORS_PER_BLK; sector++ ) { /* Loop to do all sectors*/ logSectNum = sector + SECTOR_OFFSET + /* Calc logical sect num */ ((Nat32)dskblk << BLK_TO_SECT_SHFT); cylinder = logSectNum / diskSectorsPerCylinder; rem = logSectNum % diskSectorsPerCylinder; addr = sector << SECTOR_SHFT; /* Calc logical mem addr*/ disk_write_port( DSK_DRV_HEAD, (rem / diskSectorsPerTrack) | DRIVE_BYTE ); disk_write_port( DSK_CYL_HI, (cylinder >> 8) ); disk_write_port( DSK_CYL_LO, (cylinder & 0xff) ); disk_write_port( DSK_SECTOR, (rem % diskSectorsPerTrack) + 1 ); if ( (rtn = diskRetry(dskSectorFunc, Bank(memblk, addr), Addr(addr))) != OK ) /* Read or write the sector*/ return( rtn ); dispatch(); /* Let someone else run */ } return( OK ); /* Did entire block OK */ } /* doDiskBlk() */ /************************************************************************/ /* Function : diskReadBlk */ /* Purpose : Read one disk block into memory block */ /* Inputs : Disk block number, memory block number */ /* Outputs : OK or disk error code */ /************************************************************************/ Errno diskReadBlk( LogBlk dskblk, LogBlk memblk ) { Reg Errno rtn; /* Return code from diskReadSector*/ if ( (rtn = checkDiskInitAndOn()) == OK ) /* Turn on the drive */ rtn = doDiskBlk( diskReadSector, dskblk, memblk ); /* Read the disk block */ checkDiskOff(); /* Schedule disk turn off*/ return( rtn ); } /* diskReadBlk() */ /************************************************************************/ /* Function : checkDiskWrite */ /* Purpose : Check to see if its time to write to disk, do it if so */ /* Inputs : Disk block number just completed in memory */ /* Outputs : OK, or ERROR if can't write hard disk */ /************************************************************************/ Errno checkDiskWrite( LogBlk dskBlk ) { Errno rtn, tmp_rtn; /* Return code from disk write */ if ( dskBlk < (dskBlksWritten + (DISK_WRITE_BLKS - 1)) ) return( OK ); /* If not time to write to disk,*/ /* just return OK */ if ( (rtn = checkDiskInitAndOn()) == OK ) /* Turn on the drive */ { /* Write all unwritten blocks */ /* Show write attempt even if error*/ for ( ; dskBlksWritten <= dskBlk; dskBlksWritten++ ) { if ( dskBlksWritten >= diskBlocks ) /* If block nmbr too big*/ rtn = NO_SPACE; /* return error */ else if ( (tmp_rtn = doDiskBlk(diskWriteSector, dskBlksWritten, MemBlk(dskBlksWritten))) != OK ) { rtn = tmp_rtn; dskBlkErrors++; } } } else dskBlkErrors++; checkDiskOff(); /* Schedule disk turn off */ return( rtn ); /* Return last write error */ } /* checkDiskWrite() */ #endif /* DISK */ @