void sub_trace_command( ataio_t *ata ) { unsigned long lba; unsigned char sc48[2]; unsigned char lba48[8]; reg_cmd_info.st2 = pio_inbyte( CB_STAT ); reg_cmd_info.as2 = pio_inbyte( CB_ASTAT ); reg_cmd_info.er2 = pio_inbyte( CB_ERR ); if ( reg_cmd_info.lbaSize == LBA48 ) { // read back ATA LBA48... sc48[0] = pio_inbyte( CB_SC ); lba48[0] = pio_inbyte( CB_SN ); lba48[1] = pio_inbyte( CB_CL ); lba48[2] = pio_inbyte( CB_CH ); pio_outbyte( CB_DC, CB_DC_HOB ); sc48[1] = pio_inbyte( CB_SC ); lba48[3] = pio_inbyte( CB_SN ); reg_cmd_info.sn2 = lba48[3]; lba48[4] = pio_inbyte( CB_CL ); reg_cmd_info.cl2 = lba48[4]; lba48[5] = pio_inbyte( CB_CH ); reg_cmd_info.ch2 = lba48[5]; lba48[6] = 0; lba48[7] = 0; reg_cmd_info.sc2 = * (u_int16_t *) sc48; reg_cmd_info.lbaHigh2 = * (u_int32_t *) ( lba48 + 4 ); reg_cmd_info.lbaLow2 = * (u_int32_t *) ( lba48 + 0 ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); } else { // read back ATA CHS, ATA LBA28 or ATAPI LBA32 reg_cmd_info.sc2 = pio_inbyte( CB_SC ); reg_cmd_info.sn2 = pio_inbyte( CB_SN ); reg_cmd_info.cl2 = pio_inbyte( CB_CL ); reg_cmd_info.ch2 = pio_inbyte( CB_CH ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); reg_cmd_info.lbaHigh2 = 0; reg_cmd_info.lbaLow2 = 0; if ( reg_cmd_info.lbaSize == LBA28 ) { lba = reg_cmd_info.dh2 & 0x0f; lba = lba << 8; lba = lba | reg_cmd_info.ch2; lba = lba << 8; lba = lba | reg_cmd_info.cl2; lba = lba << 8; lba = lba | reg_cmd_info.sn2; reg_cmd_info.lbaLow2 = lba; } } trc_cht(ata); }
void sub_setup_command( ataio_t *ata ) { unsigned char dev75; unsigned char fr48[2]; unsigned char sc48[2]; unsigned char lba48[8]; // determine value of Device (Drive/Head) register bits 7 and 5 dev75 = 0; // normal value if ( ata->reg_incompat_flags & REG_INCOMPAT_DEVREG ) dev75 = CB_DH_OBSOLETE; // obsolete value // WARNING: THIS CODE IS DESIGNED FOR A STUPID PROCESSOR // LIKE INTEL X86 THAT IS Little-Endian, THAT IS, A // PROCESSOR THAT STORES DATA IN MEMORY IN THE WRONG // BYTE ORDER !!! * (u_int16_t *) fr48 = reg_cmd_info.fr1; * (u_int16_t *) sc48 = reg_cmd_info.sc1; * (u_int32_t *) ( lba48 + 4 ) = reg_cmd_info.lbaHigh1; * (u_int32_t *) ( lba48 + 0 ) = reg_cmd_info.lbaLow1; pio_outbyte( CB_DC, reg_cmd_info.dc1 ); if ( reg_cmd_info.lbaSize == LBA28 ) { // in ATA LBA28 mode reg_cmd_info.fr1 = fr48[0]; pio_outbyte( CB_FR, fr48[0] ); reg_cmd_info.sc1 = sc48[0]; pio_outbyte( CB_SC, sc48[0] ); reg_cmd_info.sn1 = lba48[0]; pio_outbyte( CB_SN, lba48[0] ); reg_cmd_info.cl1 = lba48[1]; pio_outbyte( CB_CL, lba48[1] ); reg_cmd_info.ch1 = lba48[2]; pio_outbyte( CB_CH, lba48[2] ); reg_cmd_info.dh1 = ( reg_cmd_info.dh1 & 0xf0 ) | ( lba48[3] & 0x0f ); pio_outbyte( CB_DH, reg_cmd_info.dh1 | dev75 ); } else if ( reg_cmd_info.lbaSize == LBA48 ) { // in ATA LBA48 mode pio_outbyte( CB_FR, fr48[1] ); pio_outbyte( CB_SC, sc48[1] ); pio_outbyte( CB_SN, lba48[3] ); pio_outbyte( CB_CL, lba48[4] ); pio_outbyte( CB_CH, lba48[5] ); reg_cmd_info.fr1 = fr48[0]; pio_outbyte( CB_FR, fr48[0] ); reg_cmd_info.sc1 = sc48[0]; pio_outbyte( CB_SC, sc48[0] ); reg_cmd_info.sn1 = lba48[0]; pio_outbyte( CB_SN, lba48[0] ); reg_cmd_info.cl1 = lba48[1]; pio_outbyte( CB_CL, lba48[1] ); reg_cmd_info.ch1 = lba48[2]; pio_outbyte( CB_CH, lba48[2] ); pio_outbyte( CB_DH, reg_cmd_info.dh1 | dev75 ); } else { // in ATA CHS or ATAPI LBA32 mode pio_outbyte( CB_FR, reg_cmd_info.fr1 ); pio_outbyte( CB_SC, reg_cmd_info.sc1 ); pio_outbyte( CB_SN, reg_cmd_info.sn1 ); pio_outbyte( CB_CL, reg_cmd_info.cl1 ); pio_outbyte( CB_CH, reg_cmd_info.ch1 ); pio_outbyte( CB_DH, reg_cmd_info.dh1 | dev75 ); } }
int sub_select( ataio_t *ata, int dev ) { unsigned char dev75; unsigned char status; // determine value of Device (Drive/Head) register bits 7 and 5 dev75 = 0; // normal value if ( ata->reg_incompat_flags & REG_INCOMPAT_DEVREG ) dev75 = CB_DH_OBSOLETE; // obsolete value // PAY ATTENTION HERE // The caller may want to issue a command to a device that doesn't // exist (for example, Exec Dev Diag), so if we see this, // just select that device, skip all status checking and return. // We assume the caller knows what they are doing! if ( ata->reg_config_info[ dev ] < REG_CONFIG_TYPE_ATA ) { // select the device and return pio_outbyte( CB_DH, ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) | dev75 ); ATA_DELAY(); return 0; } // The rest of this is the normal ATA stuff for device selection // and we don't expect the caller to be selecting a device that // does not exist. // We don't know which drive is currently selected but we should // wait BSY=0 and DRQ=0. Normally both BSY=0 and DRQ=0 // unless something is very wrong! trc_llt( 0, 0, TRC_LLT_PNBSY ); while ( 1 ) { status = pio_inbyte( CB_STAT ); if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == 0 ) break; if ( tmr_chk_timeout() ) { trc_llt( 0, 0, TRC_LLT_TOUT ); reg_cmd_info.to = 1; reg_cmd_info.ec = 11; trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR ); reg_cmd_info.st2 = status; reg_cmd_info.as2 = pio_inbyte( CB_ASTAT ); reg_cmd_info.er2 = pio_inbyte( CB_ERR ); reg_cmd_info.sc2 = pio_inbyte( CB_SC ); reg_cmd_info.sn2 = pio_inbyte( CB_SN ); reg_cmd_info.cl2 = pio_inbyte( CB_CL ); reg_cmd_info.ch2 = pio_inbyte( CB_CH ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); return 1; } } // Here we select the drive we really want to work with by // setting the DEV bit in the Drive/Head register. pio_outbyte( CB_DH, ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) | dev75 ); ATA_DELAY(); // Wait for the selected device to have BSY=0 and DRQ=0. // Normally the drive should be in this state unless // something is very wrong (or initial power up is still in // progress). trc_llt( 0, 0, TRC_LLT_PNBSY ); while ( 1 ) { status = pio_inbyte( CB_STAT ); if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == 0 ) break; if ( tmr_chk_timeout() ) { trc_llt( 0, 0, TRC_LLT_TOUT ); reg_cmd_info.to = 1; reg_cmd_info.ec = 12; trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR ); reg_cmd_info.st2 = status; reg_cmd_info.as2 = pio_inbyte( CB_ASTAT ); reg_cmd_info.er2 = pio_inbyte( CB_ERR ); reg_cmd_info.sc2 = pio_inbyte( CB_SC ); reg_cmd_info.sn2 = pio_inbyte( CB_SN ); reg_cmd_info.cl2 = pio_inbyte( CB_CL ); reg_cmd_info.ch2 = pio_inbyte( CB_CH ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); return 1; } } // All done. The return values of this function are described in // ATAIO.H. if ( reg_cmd_info.ec ) return 1; return 0; }
void sub_setup_command( void ) { unsigned char fr48[2]; unsigned char sc48[2]; unsigned char lba48[8]; // WARNING: THIS CODE IS DESIGNED FOR A STUPID PROCESSOR // LIKE INTEL X86 THAT IS Little-Endian, THAT IS, A // PROCESSOR THAT STORES DATA IN MEMORY IN THE WRONG // BYTE ORDER !!! * (unsigned int *) fr48 = reg_cmd_info.fr1; * (unsigned int *) sc48 = reg_cmd_info.sc1; * (unsigned long *) ( lba48 + 4 ) = reg_cmd_info.lbaHigh1; * (unsigned long *) ( lba48 + 0 ) = reg_cmd_info.lbaLow1; pio_outbyte( CB_DC, reg_cmd_info.dc1 ); if ( reg_cmd_info.lbaSize == LBA28 ) { // in ATA LBA28 mode pio_outbyte( CB_FR, fr48[0] ); pio_outbyte( CB_SC, sc48[0] ); reg_cmd_info.sn1 = lba48[0]; pio_outbyte( CB_SN, lba48[0] ); reg_cmd_info.cl1 = lba48[1]; pio_outbyte( CB_CL, lba48[1] ); reg_cmd_info.ch1 = lba48[2]; pio_outbyte( CB_CH, lba48[2] ); pio_outbyte( CB_DH, ( reg_cmd_info.dh1 & 0xf0 ) | ( lba48[3] & 0x0f ) ); } else if ( reg_cmd_info.lbaSize == LBA48 ) { // in ATA LBA48 mode pio_outbyte( CB_FR, fr48[1] ); pio_outbyte( CB_SC, sc48[1] ); pio_outbyte( CB_SN, lba48[3] ); pio_outbyte( CB_CL, lba48[4] ); pio_outbyte( CB_CH, lba48[5] ); pio_outbyte( CB_FR, fr48[0] ); pio_outbyte( CB_SC, sc48[0] ); reg_cmd_info.sn1 = lba48[0]; pio_outbyte( CB_SN, lba48[0] ); reg_cmd_info.cl1 = lba48[1]; pio_outbyte( CB_CL, lba48[1] ); reg_cmd_info.ch1 = lba48[2]; pio_outbyte( CB_CH, lba48[2] ); pio_outbyte( CB_DH, reg_cmd_info.dh1 ); } else { // in ATA CHS or ATAPI LBA32 mode pio_outbyte( CB_FR, reg_cmd_info.fr1 ); pio_outbyte( CB_SC, reg_cmd_info.sc1 ); pio_outbyte( CB_SN, reg_cmd_info.sn1 ); pio_outbyte( CB_CL, reg_cmd_info.cl1 ); pio_outbyte( CB_CH, reg_cmd_info.ch1 ); pio_outbyte( CB_DH, reg_cmd_info.dh1 ); } }
int sub_select( int dev ) { unsigned char status; // PAY ATTENTION HERE // The caller may want to issue a command to a device that doesn't // exist (for example, Exec Dev Diag), so if we see this, // just select that device, skip all status checking and return. // We assume the caller knows what they are doing! if ( reg_config_info[ dev ] < REG_CONFIG_TYPE_ATA ) { // select the device and return pio_outbyte( CB_DH, dev ? CB_DH_DEV1 : CB_DH_DEV0 ); delay(4); return 0; } // The rest of this is the normal ATA stuff for device selection // and we don't expect the caller to be selecting a device that // does not exist. // We don't know which drive is currently selected but we should // wait for it to be not BUSY. Normally it will be not BUSY // unless something is very wrong! while ( 1 ) { status = pio_inbyte( CB_STAT ); if ( ( status & CB_STAT_BSY ) == 0 ) break; if ( tmr_chk_timeout() ) { reg_cmd_info.to = 1; reg_cmd_info.ec = 11; reg_cmd_info.st2 = status; reg_cmd_info.as2 = pio_inbyte( CB_ASTAT ); reg_cmd_info.er2 = pio_inbyte( CB_ERR ); reg_cmd_info.sc2 = pio_inbyte( CB_SC ); reg_cmd_info.sn2 = pio_inbyte( CB_SN ); reg_cmd_info.cl2 = pio_inbyte( CB_CL ); reg_cmd_info.ch2 = pio_inbyte( CB_CH ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); return 1; } } // Here we select the drive we really want to work with by // putting 0xA0 or 0xB0 in the Drive/Head register (1f6). pio_outbyte( CB_DH, dev ? CB_DH_DEV1 : CB_DH_DEV0 ); delay(4); // If the selected device is an ATA device, // wait for it to have READY and SEEK COMPLETE // status. Normally the drive should be in this state unless // something is very wrong (or initial power up is still in // progress). For any other type of device, just wait for // BSY=0 and assume the caller knows what they are doing. while ( 1 ) { status = pio_inbyte( CB_STAT ); if ( reg_config_info[ dev ] == REG_CONFIG_TYPE_ATA ) { if ( ( status & ( CB_STAT_BSY | CB_STAT_RDY | CB_STAT_SKC ) ) == ( CB_STAT_RDY | CB_STAT_SKC ) ) break; } else { if ( ( status & CB_STAT_BSY ) == 0 ) break; } if ( tmr_chk_timeout() ) { reg_cmd_info.to = 1; reg_cmd_info.ec = 12; reg_cmd_info.st2 = status; reg_cmd_info.as2 = pio_inbyte( CB_ASTAT ); reg_cmd_info.er2 = pio_inbyte( CB_ERR ); reg_cmd_info.sc2 = pio_inbyte( CB_SC ); reg_cmd_info.sn2 = pio_inbyte( CB_SN ); reg_cmd_info.cl2 = pio_inbyte( CB_CL ); reg_cmd_info.ch2 = pio_inbyte( CB_CH ); reg_cmd_info.dh2 = pio_inbyte( CB_DH ); return 1; } } // All done. The return values of this function are described in // ATAIO.H. if ( reg_cmd_info.ec ) return 1; return 0; }