int main( int argc, char *argv[] )
{
HBA_MEM myHBAMEM;
HBA_PORT myHBAPORT;
BYTE tempbuff1[1024], *databuff;
unsigned long tmpADDR, HBA_addr, PORT_addr;
BYTE tempbuff2[1024], *tablebuff;
HBA_CMD_TBL *myCMDTABLE;
HBA_CMD_HEADER myCMDHEADER;
FIS_REG_H2D *myCFIS;
HBA_PRDT_ENTRY *myPRDT;
int myPORTnum;
int i;
unsigned char ctemp;
memset(tempbuff1, 0xAA, 1024);
memset(tempbuff2, 0, 1024);
memset(&myCMDHEADER, 0, sizeof(HBA_CMD_HEADER));
//命令头CMDHEADER
myCMDHEADER.cfl= sizeof(FIS_REG_H2D)/sizeof(DWORD); // Command FIS size
myCMDHEADER.w= 0; // Read from device 从设备读
myCMDHEADER.prdtl = 1; // PRDT entries count 1表示1个
tmpADDR=(unsigned long)FP_SEG(tempbuff2)*16+(unsigned long)FP_OFF(tempbuff2);
tmpADDR=(tmpADDR & 0xffffff00) + 0x100 ; //tmpADDR 要128字节对齐,这里取256字节
myCMDHEADER.ctba=tmpADDR;
tablebuff=MK_FP((unsigned int)(tmpADDR>>4), (unsigned int)(tmpADDR & 0xf) ); // 一定要加(unsigned int),不然生成的地址为0
printf("tablebuff SEG=%04X OFF=%04X FLAT ADDR=%08lX \n", FP_SEG(tablebuff), FP_OFF(tablebuff) , tmpADDR);
//命令表CMDTABLE
//命令包
myCMDTABLE=(HBA_CMD_TBL *)(tablebuff);
//注意“线性地址”与 “指针地址” 的不同,这里tablebuff(指针地址) 不能写成 tmpADDR(线性地址)
myCFIS=(FIS_REG_H2D *) (myCMDTABLE);
myCFIS->fis_type = 0x27; //FIS_TYPE_REG_H2D
myCFIS->command =0xec ; // 0xEC ATA_CMD_IDENTIFY
myCFIS->device = 0; // Master device
myCFIS->c = 1; // Write command register 1表示这是一个命令
//PRDT ENTRY
myPRDT=(HBA_PRDT_ENTRY *)(myCMDTABLE->prdt_entry);
tmpADDR=(unsigned long)FP_SEG(tempbuff1)*16+(unsigned long)FP_OFF(tempbuff1);
tmpADDR=(tmpADDR & 0xfffffff0) + 0x10 ; //tmpADDR 要2字节对齐,这里取多一些
databuff=MK_FP((unsigned int)(tmpADDR>>4), (unsigned int)(tmpADDR & 0xf) ); // 一定要加(unsigned int),不然生成的地址为0
printf("databuff SEG=%04X OFF=%04X FLAT ADDR=%08lX \n", FP_SEG(databuff), FP_OFF(databuff) , tmpADDR);
myPRDT->dba= tmpADDR;
myPRDT->dbc1= 999; //表示长度是1000字节
myPRDT->dbc2= 0;
myPRDT->i= 1;
printf("COMMAND HEADER in hex is:\n");
mydisplay( (unsigned char *)&myCMDHEADER, 32 );
printf("COMMAND TABLE in hex is:\n");
mydisplay( (unsigned char *)myCMDTABLE, 144 );
printf("press a key...\n");getchar();
//读HBA MEM
if(argc<3)
{
printf("you must input HBA addr, port number!");
return 0;
}
//得到命令行的HBA ADDR
if(strlen(argv[1]) != 8) { printf("HBA ADDR must be 8 chars long!"); return 0;}
HBA_addr=0;
for(i=0;i< 8;i++)
{
argv[1] = toupper(argv[1]); //转大写
ctemp=(unsigned char)argv[1];
if (ctemp>=0x30 && ctemp<=0x39)
{
ctemp=ctemp-0x30;
}
else if (ctemp>=0x41 && ctemp<=0x46)
{
ctemp=ctemp-55;
}
else
{ printf("HBA ADDR char error"); return 0; }
HBA_addr+=((unsigned long)ctemp) << (4*(7-i));
}
//得到命令行的PORT口
myPORTnum= atoi(argv[2]);
if(myPORTnum<0 || myPORTnum>31 ) {printf("PORT NUMBER error!"); return 0; }
PORT_addr= HBA_addr + 256 + myPORTnum*128;
printf ("HBA addr=%08lXH PORT addr=%08lXH \n",HBA_addr, PORT_addr);
//读和显示MEM
memmove( HBA_addr , (unsigned long)FP_SEG(&myHBAMEM)*16+(unsigned long)FP_OFF(&myHBAMEM), 256 ); //源,目的,字节数(应为偶数)
memmove( PORT_addr , (unsigned long)FP_SEG(&myHBAPORT)*16+(unsigned long)FP_OFF(&myHBAPORT), 128 ); //源,目的,字节数(应为偶数)
printf("HBA MEM in hex is:\n");
mydisplay( (unsigned char *)&myHBAMEM, 256);
printf("press a key...\n");getchar();
printf("PORT MEM in hex is:\n");
mydisplay( (unsigned char *)&myHBAPORT, 128);
printf("press a key...\n");getchar();
//判断各个取值是否正常
if( !(myHBAMEM.ghc >> 31) ) { printf(" ERROR, AHCI NOT ENABLE "); return 0;}
if( myHBAMEM.bohc ) { printf(" ERROR, BIOS OR OS is controling HBA"); return 0;}
if( !( myHBAMEM.pi & ((DWORD)1 << myPORTnum) ) ) { printf(" ERROR, NO DEVICE ON THAT PORT"); return 0;}
if( myHBAPORT.clbu || myHBAPORT.fbu ) { printf(" ERROR, clbu or fbu ERROR"); return 0;}
if( (!myHBAPORT.clb) || (!myHBAPORT.fb) ) { printf(" ERROR, clb or fb ERROR"); return 0;}
if( myHBAPORT.is ) { printf(" ERROR, PxIS NOT ZERO"); return 0;}
if( myHBAPORT.serr ) { printf(" ERROR, PxSERR NOT ZERO"); return 0;}
if( myHBAPORT.tfd & 0x89 ) { printf(" ERROR, ERR or DRQ or BSY NOT ZERO"); return 0;}
//PxTFD.STS.BSY(bit7)=0,PxTFD.STS.DRQ(bit3)=0,PxTFD.STS.ERR(bit0)=0
if( (myHBAPORT.ssts & 0x0f) !=3 ) { printf(" ERROR, PxSSTS.DET is not 3"); return 0;} //PxSSTS.DET(bit3:0) = 3
if( (myHBAPORT.cmd & 0x8000) ) { printf(" ERROR, PxCMD.CR a command is running"); return 0;} //PxCMD.CR(bit15)=0,FR(bit14)=0
if( (myHBAPORT.cmd & 0x4000) ) { printf(" ERROR, PxCMD.FR RFIS is receiving"); return 0;}
if( myHBAPORT.ci || myHBAPORT.sact ) { printf(" ERROR, command slot is not all free"); return 0;}
//这里为简单起见,需SLOT全部空闲!即要使用SLOT0
//把COMMAND HEADER拷入SLOT
memmove( (unsigned long)FP_SEG(&myCMDHEADER)*16+(unsigned long)FP_OFF(&myCMDHEADER) , myHBAPORT.clb, 32 ); //源,目的,字节数(应为偶数)
printf("HAVE COPY COMMAND HEADER TO SLOT0 press a key...\n"); getchar();
//发送命令
myWRITEMEM_DWORD( PORT_addr+0x18, myREADMEM_DWORD( PORT_addr+0x18) | 0x10 ); //设置PxCMD.FRE(bit4)=1 使能接收FIS
printf("HAVE SET PxCMD.FRE press a key...\n"); getchar();
printf("PxCMD is %08lX\n", myREADMEM_DWORD( PORT_addr+0x18));
myWRITEMEM_DWORD( PORT_addr+0x18, myREADMEM_DWORD( PORT_addr+0x18) | 0x01 ); //设置PxCMD.ST(bit0)=1 使能命令运行
printf("HAVE SET PxCMD.ST press a key...\n"); getchar();
printf("PxCMD is %08lX\n", myREADMEM_DWORD( PORT_addr+0x18));
myWRITEMEM_DWORD( PORT_addr+0x38, myHBAPORT.ci | 0x01 ); //写PxCI.CI相应位,让HBA发送命令。这里是SLOT0
//判断命令完成
delay(1000); //延时1S
if( myREADMEM_DWORD(PORT_addr+0x38) ) {printf(" ERROR, PxCI.CI not return zero"); return 0; } //PxCI.CI必须清零
if( myREADMEM_DWORD(PORT_addr+0x10) & 0x40000000 ) {printf(" ERROR, PxIS.TFES is 1"); return 0; } //PxIS.TFES(bit30) 不能为1
//显示收到的数据
printf("data buff in hex is:\n");
mydisplay(databuff, 256);
printf("press a key...\n");getchar();
mydisplay(databuff+256, 256);
return 0;
}
文章评论(0条评论)
登录后参与讨论