901 lines
24 KiB
Plaintext
901 lines
24 KiB
Plaintext
BoolU4 RAMRBlks(LTPartition *p,U1 *buf,U8 blk,U8 cnt)
|
|
{
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
MemCpy(buf,bdev->RAM_disk+blk*BLK_SIZE,cnt*BLK_SIZE);
|
|
return TRUE;
|
|
}
|
|
|
|
BoolU4 RAMWBlks(LTPartition *p,U1 *buf,U8 blk,U8 cnt)
|
|
{
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
MemCpy(bdev->RAM_disk+blk*BLK_SIZE,buf,cnt*BLK_SIZE);
|
|
return TRUE;
|
|
}
|
|
|
|
BoolU4 FileRBlks(LTPartition *p,U1 *buf,U8 blk,U8 cnt)
|
|
{
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
if (!bdev->f)
|
|
throw(EXCEPT_PARTITION,5);
|
|
if (!FRBlks(bdev->f,buf,blk,cnt))
|
|
throw(EXCEPT_PARTITION,6);
|
|
FSync(bdev->f);
|
|
return TRUE;
|
|
}
|
|
|
|
BoolU4 FileWBlks(LTPartition *p,U1 *buf,U8 blk,U8 cnt)
|
|
{
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
if (!bdev->f)
|
|
throw(EXCEPT_PARTITION,7);
|
|
if (!FWBlks(bdev->f,buf,blk,cnt))
|
|
throw(EXCEPT_PARTITION,8);
|
|
FSync(bdev->f);
|
|
return TRUE;
|
|
}
|
|
|
|
#define FDC_p0 0
|
|
#define FDC_p1 1
|
|
#define FDC_DOR 2
|
|
#define FDC_p3 3
|
|
#define FDC_STATUS 4
|
|
#define FDC_DATA 5
|
|
#define FDC_DIR 7
|
|
#define FDC_DCR 7
|
|
|
|
void Irq06Handler()
|
|
{
|
|
Bts(&sys_irq_flags,6);
|
|
}
|
|
|
|
|
|
void FDCFlushStatus(LTBlkDev *bdev)
|
|
{
|
|
U1 b;
|
|
I8 i;
|
|
MemSet(bdev->status,0,32);
|
|
i=0;
|
|
while (i<32) {
|
|
b=InP(bdev->base0+FDC_STATUS);
|
|
if (b & 0x80) {
|
|
if (b & 0x40)
|
|
bdev->status[i++]=InP(bdev->base0+FDC_DATA);
|
|
else
|
|
break;
|
|
}
|
|
SwapInNext;
|
|
}
|
|
if (i==32)
|
|
throw(EXCEPT_FDC,2);
|
|
bdev->status[0]=bdev->status[0] & 0xC8; //clear non-error bits
|
|
bdev->last_jiffy=jiffies;
|
|
}
|
|
|
|
void FDCWaitIrq(LTBlkDev *bdev)
|
|
{
|
|
BoolU4 old_flags=GetFlags;
|
|
Sti;
|
|
while (!Btr(&sys_irq_flags,bdev->irq)) {
|
|
/*
|
|
if (!(InP(bdev->base0+FDC_p0) & 0x80)) //Pending IRQ?
|
|
throw(EXCEPT_FDC,1);
|
|
*/
|
|
SwapInNext;
|
|
}
|
|
SetFlags(old_flags);
|
|
FDCFlushStatus(bdev);
|
|
}
|
|
|
|
|
|
void FDCSendCmdU1(LTBlkDev *bdev,U1 v)
|
|
{
|
|
FDCFlushStatus(bdev);
|
|
OutP(bdev->base0+FDC_DATA,v);
|
|
}
|
|
|
|
void FDCSeek(LTBlkDev *bdev,U1 cyl, U1 head)
|
|
{
|
|
FDCSendCmdU1(bdev,0x0F);
|
|
FDCSendCmdU1(bdev,head<<2);
|
|
FDCSendCmdU1(bdev,cyl);
|
|
FDCWaitIrq(bdev);
|
|
}
|
|
|
|
void FDCFree(LTBlkDev *bdev)
|
|
{
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
}
|
|
|
|
void MonitorFDCTsk()
|
|
{
|
|
LTBlkDev *bdev;
|
|
Preempt(OFF);
|
|
bdev=Fs->user_aux0;
|
|
CheckLTBlkDev(bdev);
|
|
while (TRUE) {
|
|
if (!Bts(&sys_irq_busy_flags,bdev->irq)) {
|
|
if (bdev->last_jiffy) {
|
|
if (jiffies > bdev->last_jiffy+JIFFY_FREQ<<1) {
|
|
FDCSeek(bdev,0,0);
|
|
FDCSeek(bdev,0,1);
|
|
OutP(bdev->base0+FDC_DOR,0x00);
|
|
bdev->last_jiffy=0;
|
|
}
|
|
}
|
|
FDCFree(bdev);
|
|
}
|
|
SwapInNext;
|
|
}
|
|
}
|
|
|
|
|
|
void FDCGet(LTBlkDev *bdev)
|
|
{
|
|
CheckLTBlkDev(bdev);
|
|
while (Bts(&sys_irq_busy_flags,bdev->irq))
|
|
SwapInNext;
|
|
Btr(&sys_irq_flags,bdev->irq);
|
|
|
|
if (!bdev->last_jiffy) {
|
|
bdev->last_jiffy=jiffies;
|
|
OutP(bdev->base0+FDC_DOR,0x00);
|
|
BusyWait(100);
|
|
OutP(bdev->base0+FDC_DOR,0x1C); //Motor ON
|
|
FDCWaitIrq(bdev);
|
|
OutP(bdev->base0+FDC_DCR,0x00); //step,Load, Unload specs
|
|
FDCSendCmdU1(bdev,0x03);
|
|
FDCSendCmdU1(bdev,0xCF);
|
|
FDCSendCmdU1(bdev,0x10);
|
|
FDCWaitIrq(bdev);
|
|
FDCSendCmdU1(bdev,0x07); //Recalibrate
|
|
FDCSendCmdU1(bdev,0x00);
|
|
FDCWaitIrq(bdev);
|
|
}
|
|
}
|
|
|
|
void FDCReset(LTBlkDev *bdev)
|
|
{
|
|
CheckLTBlkDev(bdev);
|
|
OutP(0x0A,0x42); //Shut down old DMA
|
|
OutP(0x09,0x02);
|
|
bdev->last_jiffy=0;
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
FDCGet(bdev);
|
|
}
|
|
|
|
BoolU4 FDCReadTrack(LTBlkDev *bdev,U1 cyl, U1 head,U8 blk)
|
|
{
|
|
I8 i;
|
|
U8 size=BLK_SIZE*FDC_DISK_SECTORS-1;
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
CheckLTBlkDev(bdev);
|
|
|
|
for (i=0;i<FDC_retries;i++) {
|
|
FDCSeek(bdev,cyl,head);
|
|
|
|
OutP(0x0A,0x42); //Shut down old DMA
|
|
OutP(0x09,0x02);
|
|
OutP(0x08,0x00); //ctrl
|
|
OutP(0x0B,0x56); //mode Read
|
|
OutP(0x0C,0);
|
|
OutP(0x04,FDC_DMA_BUF & 0xFF); //addr
|
|
OutP(0x04,(FDC_DMA_BUF>>8) & 0xFF);
|
|
OutP(0x81,FDC_DMA_BUF>>16); //set page
|
|
OutP(0x0C,0);
|
|
OutP(0x05,size.u1[0]); //cnt
|
|
OutP(0x05,size.u1[1]);
|
|
OutP(0x0A,0x02); //Start new DMA
|
|
OutP(0x09,0x06);
|
|
|
|
FDCSendCmdU1(bdev,0x62);
|
|
FDCSendCmdU1(bdev,head<<2);
|
|
FDCSendCmdU1(bdev,cyl);
|
|
FDCSendCmdU1(bdev,head);
|
|
FDCSendCmdU1(bdev,1); //sector
|
|
FDCSendCmdU1(bdev,BLK_SIZE>>8);
|
|
FDCSendCmdU1(bdev,FDC_DISK_SECTORS); //last sec
|
|
FDCSendCmdU1(bdev,0x1B); //gap
|
|
FDCSendCmdU1(bdev,0xFF);
|
|
FDCWaitIrq(bdev);
|
|
if (bdev->status[0] || bdev->status[1] ||
|
|
bdev->status[2]) {
|
|
coutln "FDC Read Error:",bdev->status[2],bdev->status[1],bdev->status[0];
|
|
FDCReset(bdev);
|
|
} else {
|
|
Preempt(old_preempt);
|
|
return TRUE;
|
|
}
|
|
}
|
|
coutln "FDC Read Failed!!! Blk:",blk;
|
|
Preempt(old_preempt);
|
|
return FALSE;
|
|
}
|
|
|
|
BoolU4 FDCRBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
LTCacheBlk *tempc;
|
|
BoolU4 okay=TRUE;
|
|
U8 l,blk2;
|
|
U1 cyl,head,sec;
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
while (cnt>0) {
|
|
if (bdev->flags & LTBDF_READ_CACHE) {
|
|
while (cnt) {
|
|
tempc=LTDCFindBlk(p,blk); //TODO preempt
|
|
if (tempc) {
|
|
MemCpy(buf,&tempc->body,BLK_SIZE);
|
|
cnt--;
|
|
buf+=BLK_SIZE;
|
|
blk++;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
if (cnt) {
|
|
l=cnt;
|
|
if (l>bdev->max_reads)
|
|
l=bdev->max_reads;
|
|
blk2=blk;
|
|
sec=blk2%FDC_DISK_SECTORS+1;blk2=blk2/FDC_DISK_SECTORS;
|
|
head=blk2%FDC_DRIVE_HEADS;
|
|
cyl=blk2/FDC_DRIVE_HEADS;
|
|
if (!FDCReadTrack(bdev,cyl,head,blk-(sec-1)))
|
|
okay=FALSE;
|
|
MemCpy(buf,FDC_DMA_BUF+BLK_SIZE*(sec-1),l*BLK_SIZE);
|
|
if (bdev->flags & LTBDF_READ_CACHE)
|
|
LTDCAdd(DriveToPartition(bdev->partition_base),
|
|
FDC_DMA_BUF,blk-(sec-1),FDC_DISK_SECTORS);
|
|
buf+=l*BLK_SIZE;
|
|
blk+=l;
|
|
cnt-=l;
|
|
disk_status_display.u2[0]=disk_status_display.u2[0]-l;
|
|
}
|
|
}
|
|
return okay;
|
|
}
|
|
|
|
BoolU4 FDCWriteBlk2(LTBlkDev *bdev,U1 *buf, U1 cyl, U1 head,U1 sec,U8 blk)
|
|
{
|
|
I8 i;
|
|
U8 size=BLK_SIZE*bdev->max_writes-1;
|
|
BoolU4 old_preempt;
|
|
|
|
old_preempt=Preempt(OFF);
|
|
for (i=0;i<FDC_retries;i++) { //Retry up to 10 times
|
|
FDCSeek(bdev,cyl,head);
|
|
|
|
MemCpy(FDC_DMA_BUF,buf,size+1);
|
|
OutP(0x0A,0x42); //Shut down old DMA
|
|
OutP(0x09,0x02);
|
|
OutP(0x08,0x00); //ctrl
|
|
OutP(0x0B,0x5A); //mode Write
|
|
OutP(0x0C,0);
|
|
OutP(0x04,FDC_DMA_BUF & 0xFF); //addr
|
|
OutP(0x04,(FDC_DMA_BUF>>8) & 0xFF);
|
|
OutP(0x81,FDC_DMA_BUF>>16); //set page
|
|
OutP(0x0C,0);
|
|
OutP(0x05,size.u1[0]); //cnt
|
|
OutP(0x05,size.u1[1]);
|
|
OutP(0x0A,0x02); //Start new DMA
|
|
OutP(0x09,0x06);
|
|
|
|
FDCSendCmdU1(bdev,0xC5);
|
|
FDCSendCmdU1(bdev,head<<2);
|
|
FDCSendCmdU1(bdev,cyl);
|
|
FDCSendCmdU1(bdev,head);
|
|
FDCSendCmdU1(bdev,sec);
|
|
FDCSendCmdU1(bdev,BLK_SIZE>>8);
|
|
FDCSendCmdU1(bdev,FDC_DISK_SECTORS); //last sec
|
|
FDCSendCmdU1(bdev,0x1B); //gap
|
|
FDCSendCmdU1(bdev,0xFF);
|
|
FDCWaitIrq(bdev);
|
|
if (bdev->status[2] || bdev->status[1] ||
|
|
bdev->status[0]) {
|
|
coutln "FDC Write Error:",bdev->status[0],bdev->status[1],bdev->status[2];
|
|
FDCReset(bdev);
|
|
} else {
|
|
Preempt(old_preempt);
|
|
return TRUE;
|
|
}
|
|
}
|
|
coutln "FDC Write Failed!!! Blk:",blk;
|
|
Preempt(old_preempt);
|
|
return FALSE;
|
|
}
|
|
|
|
BoolU4 FDCWBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
BoolU4 okay=TRUE;
|
|
U8 l,blk2;
|
|
U1 cyl,head,sec;
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
while (cnt>0) {
|
|
l=cnt;
|
|
if (l>bdev->max_writes)
|
|
l=bdev->max_writes;
|
|
blk2=blk;
|
|
sec=blk2%FDC_DISK_SECTORS+1;blk2=blk2/FDC_DISK_SECTORS;
|
|
head=blk2%FDC_DRIVE_HEADS;
|
|
cyl=blk2/FDC_DRIVE_HEADS;
|
|
if (!FDCWriteBlk2(bdev,buf,cyl,head,sec,blk))
|
|
okay=FALSE;
|
|
buf+=l*BLK_SIZE;
|
|
blk+=l;
|
|
cnt-=l;
|
|
disk_status_display.u2[0]=disk_status_display.u2[0]-l;
|
|
}
|
|
return okay;
|
|
}
|
|
|
|
|
|
|
|
//The following definitions were copied from Linux source code
|
|
/* ATA/ATAPI Cmds pre T13 Spec */
|
|
#define WIN_NOP 0x00
|
|
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
|
|
#define WIN_SRST 0x08 /* ATAPI soft reset cmd */
|
|
#define WIN_DEV_RESET 0x08
|
|
#define WIN_RESTORE 0x10
|
|
#define WIN_READ 0x20 /* 28-Bit */
|
|
#define WIN_READ_EXT 0x24 /* 48-Bit */
|
|
#define WIN_READDMA_EXT 0x25 /* 48-Bit */
|
|
#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */
|
|
#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
|
|
#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
|
|
#define WIN_WRITE 0x30 /* 28-Bit */
|
|
#define WIN_WRITE_EXT 0x34 /* 48-Bit */
|
|
#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
|
|
#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
|
|
#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
|
|
#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
|
|
#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
|
|
#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */
|
|
#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
|
|
#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
|
|
#define WIN_FORMAT 0x50
|
|
#define WIN_INIT 0x60
|
|
#define WIN_SEEK 0x70
|
|
#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
|
|
#define WIN_DIAGNOSE 0x90
|
|
#define WIN_SPECIFY 0x91 /* set Drive geometry translation */
|
|
#define WIN_DOWNLOAD_MICROCODE 0x92
|
|
#define WIN_STANDBYNOW2 0x94
|
|
#define WIN_SETIDLE2 0x97
|
|
#define WIN_CHECKPOWERMODE2 0x98
|
|
#define WIN_SLEEPNOW2 0x99
|
|
#define WIN_PACKETCMD 0xA0 /* Send a packet cmd. */
|
|
#define WIN_PIDENTIFY 0xA1 /* IDEntify ATAPI dev */
|
|
#define WIN_QUEUED_SERVICE 0xA2
|
|
#define WIN_SMART 0xB0 /* self-monitoring and reporting */
|
|
#define CFA_ERASE_SECTORS 0xC0
|
|
#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
|
|
#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
|
|
#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
|
|
#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
|
|
#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
|
|
#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
|
|
#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
|
|
#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
|
|
#define WIN_GETMEDIASTATUS 0xDA
|
|
#define WIN_DOORLOCK 0xDE /* lock door ON removable drives */
|
|
#define WIN_DOORUNLOCK 0xDF /* unlock door ON removable drives */
|
|
#define WIN_STANDBYNOW1 0xE0
|
|
#define WIN_IDLEIMMEDIATE 0xE1 /* force Drive to become "ready" */
|
|
#define WIN_STANDBY 0xE2 /* Set dev in Standby Mode */
|
|
#define WIN_SETIDLE1 0xE3
|
|
#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
|
|
#define WIN_CHECKPOWERMODE1 0xE5
|
|
#define WIN_SLEEPNOW1 0xE6
|
|
#define WIN_FLUSH_CACHE 0xE7
|
|
#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
|
|
#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
|
|
#define WIN_IDENTIFY 0xEC /* ask Drive to IDEntify itself */
|
|
#define WIN_MEDIAELTECT 0xED
|
|
#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
|
|
#define WIN_SETFEATURES 0xEF /* set special Drive features */
|
|
#define EXAU1_ENABLE_NEST 0xF0
|
|
#define WIN_SECURITY_SET_PASS 0xF1
|
|
#define WIN_SECURITY_UNLOCK 0xF2
|
|
#define WIN_SECURITY_ERASE_PREPARE 0xF3
|
|
#define WIN_SECURITY_ERASE_UNIT 0xF4
|
|
#define WIN_SECURITY_FREEZE_LOCK 0xF5
|
|
#define WIN_SECURITY_DISABLE 0xF6
|
|
#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
|
|
#define WIN_SET_MAX 0xF9
|
|
#define DISABLE_SEAGATE 0xFB
|
|
|
|
/* Bits of HD_STATUS */
|
|
#define ERR_STAT 0x01
|
|
#define INDEX_STAT 0x02
|
|
#define ECC_STAT 0x04 /* Corrected error */
|
|
#define DRQ_STAT 0x08
|
|
#define SEEK_STAT 0x10
|
|
#define WRERR_STAT 0x20
|
|
#define READY_STAT 0x40
|
|
#define BUSY_STAT 0x80
|
|
; /*here for compiler bug*/
|
|
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
|
|
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
|
|
#define BAD_STAT (BAD_R_STAT | DRQ_STAT)
|
|
#define DRIVE_READY (READY_STAT | SEEK_STAT)
|
|
#define DATA_READY (DRQ_STAT)
|
|
|
|
#define IDE_DATA_REG 0
|
|
#define IDE_FEATURE_REG 1
|
|
#define IDE_NSECTOR_REG 2
|
|
#define IDE_SECTOR_REG 3
|
|
#define IDE_LCYL_REG 4
|
|
#define IDE_HCYL_REG 5
|
|
#define IDE_SELECT_REG 6
|
|
#define IDE_STATUS 7
|
|
#define IDE_CMD 7
|
|
#define IDE_CONTROL_REG 0
|
|
|
|
void Irq0EHandler()
|
|
{
|
|
Bts(&sys_irq_flags,14);
|
|
}
|
|
|
|
void Irq0FHandler()
|
|
{
|
|
Bts(&sys_irq_flags,15);
|
|
}
|
|
|
|
void ATASelectBlk28(LTBlkDev *bdev,U8 blk,U8 cnt)
|
|
{
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SECTOR_REG,blk);
|
|
OutP(bdev->base0+IDE_NSECTOR_REG,cnt);
|
|
OutP(bdev->base0+IDE_LCYL_REG,blk.u1[1]);
|
|
OutP(bdev->base0+IDE_HCYL_REG,blk.u1[2]);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4|blk.u1[3]);
|
|
}
|
|
|
|
/*************
|
|
void ATASelectBlk48(LTBlkDev *bdev,U8 blk,U8 cnt)
|
|
{//Untested
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_NSECTOR_REG,cnt.u1[1]);
|
|
OutP(bdev->base0+IDE_SECTOR_REG,blk_lo.u1[3]);
|
|
OutP(bdev->base0+IDE_LCYL_REG,blk_hi);
|
|
OutP(bdev->base0+IDE_HCYL_REG,blk_hi.u1[1]);
|
|
|
|
OutP(bdev->base0+IDE_NSECTOR_REG,cnt);
|
|
OutP(bdev->base0+IDE_SECTOR_REG,blk_lo);
|
|
OutP(bdev->base0+IDE_LCYL_REG,blk_lo.u1[1]);
|
|
OutP(bdev->base0+IDE_HCYL_REG,blk_lo.u1[2]);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
}
|
|
***************/
|
|
|
|
void IDEWaitNotBusy(LTBlkDev *bdev)
|
|
{
|
|
while (InP(bdev->base0+IDE_STATUS) & BUSY_STAT)
|
|
SwapInNext;
|
|
}
|
|
|
|
void ATANop(LTBlkDev *bdev)
|
|
{
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_FEATURE_REG,0);
|
|
OutP(bdev->base0+IDE_CMD,WIN_NOP);
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
void ATACmd(LTBlkDev *bdev,U1 cmd)
|
|
{
|
|
OutP(bdev->base0+IDE_FEATURE_REG,0);
|
|
OutP(bdev->base0+IDE_CMD,cmd);
|
|
bdev->last_jiffy=jiffies;
|
|
}
|
|
|
|
/*******
|
|
U8 ATAPIStat(LTBlkDev *bdev)
|
|
{
|
|
return InP(bdev->base0+IDE_STATUS)+
|
|
256*(InP(bdev->base0+IDE_NSECTOR_REG)+
|
|
256* InP(bdev->base0+IDE_FEATURE_REG) );
|
|
}
|
|
**********/
|
|
|
|
void ATAPIWritePktWord(LTBlkDev *bdev,U2 w)
|
|
{
|
|
while (!(InP(bdev->base0+IDE_STATUS)&DATA_READY))
|
|
SwapInNext;
|
|
OutPW(bdev->base0+IDE_DATA_REG,w.u1[1]+256*w.u1[0]);
|
|
bdev->last_jiffy=jiffies;
|
|
}
|
|
|
|
void IDEWaitForDrive(LTBlkDev *bdev)
|
|
{
|
|
while (Bts(&sys_irq_busy_flags,bdev->irq))
|
|
SwapInNext;
|
|
Btr(&sys_irq_flags,bdev->irq);
|
|
}
|
|
|
|
/********
|
|
void IDEWaitForIrq(LTBlkDev *bdev)
|
|
{
|
|
BoolU4 old_flags=GetFlags;
|
|
Sti;
|
|
while (!Btr(&sys_irq_flags,bdev->irq))
|
|
SwapInNext;
|
|
SetFlags(old_flags);
|
|
}
|
|
*********/
|
|
|
|
void ATAPISeek(LTBlkDev *bdev,U8 blk)
|
|
{
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0x2B00); //Seek
|
|
ATAPIWritePktWord(bdev,blk>>16);
|
|
ATAPIWritePktWord(bdev,blk);
|
|
ATAPIWritePktWord(bdev,0);
|
|
ATAPIWritePktWord(bdev,0);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
void ATAPIStartStop(LTBlkDev *bdev,BoolU4 start)
|
|
{
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0x1B00); //Start/Stop
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
if (start)
|
|
ATAPIWritePktWord(bdev,0x0100);
|
|
else
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
void IDEInit(LTBlkDev *bdev,BoolU4 unlock)
|
|
{
|
|
U8 blk=0x0F000000; //TODO:fix this?
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
CheckLTBlkDev(bdev);
|
|
if (unlock) {
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
IDEWaitForDrive(bdev);
|
|
}
|
|
// not using irqs
|
|
// Btr(&sys_irq_flags,bdev->irq);
|
|
|
|
if (!(bdev->flags & LTBDF_HAS_BEEN_RESET)) {
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
ATACmd(bdev,WIN_DEV_RESET);
|
|
IDEWaitNotBusy(bdev);
|
|
bdev->flags=bdev->flags | LTBDF_HAS_BEEN_RESET;
|
|
}
|
|
if (bdev->type==LTBDT_ATA) {
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
ATACmd(bdev,WIN_READ_NATIVE_MAX);
|
|
IDEWaitNotBusy(bdev);
|
|
//TODO:do this right
|
|
ATASelectBlk28(bdev,blk,0);
|
|
ATACmd(bdev,WIN_SET_MAX);
|
|
IDEWaitNotBusy(bdev);
|
|
} else {
|
|
ATAPIStartStop(bdev,TRUE);
|
|
ATAPISeek(bdev,0);
|
|
}
|
|
Btr(&sys_irq_flags,bdev->irq);
|
|
if (unlock)
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
Preempt(old_preempt);
|
|
}
|
|
|
|
/**********
|
|
void IDEWaitReady(LTBlkDev *bdev)
|
|
{
|
|
U8 i=0;
|
|
while (!(InP(bdev->base0+IDE_STATUS) & READY_STAT)) {
|
|
if (!(++i & 0xFFF))
|
|
IDEInit(bdev,FALSE);
|
|
ATANop(bdev);
|
|
SwapInNext;
|
|
}
|
|
}
|
|
***********/
|
|
|
|
void ATAPIWaitReady(LTBlkDev *bdev)
|
|
{
|
|
U8 pass=0;
|
|
BoolU4 cont;
|
|
do {
|
|
IDEWaitNotBusy(bdev);
|
|
if (pass)
|
|
SwapInNext;
|
|
ATANop(bdev);
|
|
if (InP(bdev->base0+IDE_STATUS) & READY_STAT) {
|
|
if (!bdev->last_jiffy || pass>16 ||
|
|
(jiffies>bdev->last_jiffy+JIFFY_FREQ<<1)) {
|
|
ATAPIStartStop(bdev,TRUE);
|
|
}
|
|
cont=FALSE;
|
|
} else {
|
|
if (pass>16)
|
|
IDEInit(bdev,FALSE);
|
|
cont=TRUE;
|
|
}
|
|
pass++;
|
|
} while (cont || InP(bdev->base0+IDE_FEATURE_REG));
|
|
}
|
|
|
|
void ATAReadBlks2(LTBlkDev *bdev,U1 *buf, U8 cnt)
|
|
{
|
|
U8 U2s_avail,sectors_avail;
|
|
while (cnt) {
|
|
while (InP(bdev->base0+IDE_STATUS) & DATA_READY!=DATA_READY)
|
|
SwapInNext;
|
|
|
|
// while (!(sectors_avail=cnt-InP(bdev->base0+IDE_NSECTOR_REG)))
|
|
// SwapInNext;
|
|
sectors_avail=1;
|
|
|
|
U2s_avail=sectors_avail*BLK_SIZE>>1;
|
|
RepInSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
|
|
buf+=U2s_avail<<1;
|
|
cnt-=sectors_avail;
|
|
}
|
|
IDEWaitNotBusy(bdev);
|
|
Btr(&sys_irq_flags,bdev->irq);
|
|
}
|
|
|
|
|
|
/***********
|
|
void ATAReadBlksExt(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{// Untested
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
IDEWaitForDrive(bdev);
|
|
ATASelectBlk48(bdev,blk,0,cnt);
|
|
ATACmd(bdev,WIN_MULTREAD_EXT);
|
|
ATAReadBlks2(bdev,buf,cnt);
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
Preempt(old_preempt);
|
|
}
|
|
*************/
|
|
|
|
void ATAReadBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
IDEWaitForDrive(bdev);
|
|
ATASelectBlk28(bdev,blk,cnt);
|
|
ATACmd(bdev,WIN_MULTREAD);
|
|
ATAReadBlks2(bdev,buf,cnt);
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
Preempt(old_preempt);
|
|
}
|
|
|
|
void ATAPIReadBlks2(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
U8 U2s_avail;
|
|
U1 *done_add=buf+cnt*bdev->blk_size;
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
|
|
if (!cnt)
|
|
return;
|
|
IDEWaitForDrive(bdev);
|
|
ATAPIWaitReady(bdev);
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0xA800);
|
|
ATAPIWritePktWord(bdev,blk.u2[1]);
|
|
ATAPIWritePktWord(bdev,blk);
|
|
ATAPIWritePktWord(bdev,cnt.u2[1]);
|
|
ATAPIWritePktWord(bdev,cnt);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
while (buf<done_add) {
|
|
while (!(InP(bdev->base0+IDE_STATUS) & DATA_READY))
|
|
SwapInNext;
|
|
if (U2s_avail=(InP(bdev->base0+IDE_HCYL_REG)<<8+InP(bdev->base0+IDE_LCYL_REG))>>1) {
|
|
if (buf+U2s_avail<<1>done_add)
|
|
U2s_avail=(done_add-buf)>>1;
|
|
RepInSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
|
|
buf+=U2s_avail<<1;
|
|
}
|
|
}
|
|
IDEWaitNotBusy(bdev);
|
|
// ATAPIStartStop(bdev,FALSE);
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
Preempt(old_preempt);
|
|
}
|
|
|
|
void ATAPIReadBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
LTPartition *p=DriveToPartition(bdev->partition_base);
|
|
U8 dv=bdev->blk_size/BLK_SIZE,l,blk2,
|
|
l2=bdev->max_reads<<1+dv<<1;
|
|
U1 *cd_buf=MAlloc(BLK_SIZE*l2);
|
|
if (cnt) {
|
|
if (blk<=bdev->max_reads)
|
|
blk2=0;
|
|
else
|
|
blk2=((blk-bdev->max_reads)/dv)*dv;
|
|
if (blk2+l2>p->size)
|
|
l2=p->size-blk2;
|
|
l=(l2+dv-1)/dv;
|
|
ATAPIReadBlks2(bdev,cd_buf,blk2/dv,l);
|
|
if (bdev->flags & LTBDF_READ_CACHE)
|
|
LTDCAdd(p,cd_buf,blk2,l*dv);
|
|
MemCpy(buf,cd_buf+(blk-blk2)*BLK_SIZE,cnt*BLK_SIZE);
|
|
}
|
|
Free(cd_buf);
|
|
}
|
|
|
|
void IDERBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
U8 l;
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
while (cnt>0) {
|
|
l=cnt;
|
|
if (l>bdev->max_reads)
|
|
l=bdev->max_reads;
|
|
if (bdev->type==LTBDT_ATAPI)
|
|
ATAPIReadBlks(bdev,buf,blk,l);
|
|
else
|
|
ATAReadBlks(bdev,buf,blk,l);
|
|
buf+=l*BLK_SIZE;
|
|
blk+=l;
|
|
cnt-=l;
|
|
disk_status_display.u2[0]=disk_status_display.u2[0]-l;
|
|
}
|
|
}
|
|
|
|
//This is for low level disk access
|
|
//Call WBlks() instead
|
|
void ATAWriteBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
U8 U2s_avail,sectors_avail;
|
|
BoolU4 old_preempt=Preempt(OFF);
|
|
IDEWaitForDrive(bdev);
|
|
ATASelectBlk28(bdev,blk,cnt);
|
|
ATACmd(bdev,WIN_MULTWRITE);
|
|
while (cnt) {
|
|
while (InP(bdev->base0+IDE_STATUS) & DRIVE_READY!=DRIVE_READY)
|
|
SwapInNext;
|
|
while (InP(bdev->base0+IDE_STATUS) & DATA_READY!=DATA_READY)
|
|
SwapInNext;
|
|
//TODO
|
|
sectors_avail=1;
|
|
U2s_avail=sectors_avail*BLK_SIZE>>1;
|
|
RepOutSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
|
|
buf+=U2s_avail<<1;
|
|
cnt-=sectors_avail;
|
|
}
|
|
IDEWaitNotBusy(bdev);
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
Preempt(old_preempt);
|
|
}
|
|
|
|
void ATAPISync(LTBlkDev *bdev)
|
|
{
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0x3500); //Sync
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
void ATAPIClose(LTBlkDev *bdev)
|
|
{
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0x5B00); //Close
|
|
ATAPIWritePktWord(bdev,0x0200);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
void ATAPIWriteBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
U8 U2s_avail;
|
|
U1 *buf2;
|
|
|
|
ATAPISeek(bdev,blk);
|
|
|
|
OutP(bdev->base0+IDE_FEATURE_REG,0);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_CMD,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0x0400); //FMT
|
|
ATAPIWritePktWord(bdev,blk.u2[1]);
|
|
ATAPIWritePktWord(bdev,blk);
|
|
ATAPIWritePktWord(bdev,cnt.u2[1]);
|
|
ATAPIWritePktWord(bdev,cnt);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
IDEWaitNotBusy(bdev);
|
|
|
|
ATAPISeek(bdev,blk);
|
|
|
|
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
|
|
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
|
|
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
|
|
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
|
|
ATACmd(bdev,WIN_PACKETCMD);
|
|
ATAPIWritePktWord(bdev,0xAA00); //Write
|
|
ATAPIWritePktWord(bdev,blk.u2[1]);
|
|
ATAPIWritePktWord(bdev,blk);
|
|
ATAPIWritePktWord(bdev,cnt.u2[1]);
|
|
ATAPIWritePktWord(bdev,cnt);
|
|
ATAPIWritePktWord(bdev,0x0000);
|
|
buf2=buf+bdev->blk_size*cnt;
|
|
while (buf<buf2) {
|
|
while (InP(bdev->base0+IDE_STATUS) & DRIVE_READY!=DRIVE_READY)
|
|
SwapInNext;
|
|
while (InP(bdev->base0+IDE_STATUS) & DATA_READY!=DATA_READY)
|
|
SwapInNext;
|
|
U2s_avail=(InP(bdev->base0+IDE_HCYL_REG)<<8+InP(bdev->base0+IDE_LCYL_REG))>>1;
|
|
if (buf+U2s_avail<<1>buf2)
|
|
U2s_avail=(buf2-buf)>>1;
|
|
if (U2s_avail) {
|
|
RepOutSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
|
|
buf+=U2s_avail<<1;
|
|
}
|
|
}
|
|
IDEWaitNotBusy(bdev);
|
|
}
|
|
|
|
//TODO: needs to be fixed so it does more than one blk at
|
|
//a time when it calls ATAWriteBlks.
|
|
void IDEWBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
|
|
{
|
|
U8 l,dv;
|
|
LTBlkDev *bdev=p->bdev;
|
|
CheckLTBlkDev(bdev);
|
|
dv=bdev->blk_size/BLK_SIZE;
|
|
if (bdev->type==LTBDT_ATAPI) {
|
|
IDEWaitForDrive(bdev);
|
|
ATAPIWaitReady(bdev);
|
|
}
|
|
while (cnt>0) {
|
|
l=cnt;
|
|
if (l>bdev->max_writes)
|
|
l=bdev->max_writes;
|
|
if (bdev->type==LTBDT_ATAPI)
|
|
ATAPIWriteBlks(bdev,buf,blk/dv,(l+dv-1)/dv);
|
|
else
|
|
ATAWriteBlks(bdev,buf,blk,l);
|
|
buf+=l*BLK_SIZE;
|
|
blk+=l;
|
|
cnt-=l;
|
|
disk_status_display.u2[0]=disk_status_display.u2[0]-l;
|
|
}
|
|
if (bdev->type==LTBDT_ATAPI) {
|
|
ATAPISync(bdev);
|
|
// ATAPIStartStop(bdev,FALSE);
|
|
Btr(&sys_irq_busy_flags,bdev->irq);
|
|
}
|
|
}
|
|
|