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 delay_400(struct ata_channel *channel) { int j = 0; for (; j < 14; j++) pio_inbyte( channel, CB_ASTAT ); }
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); }
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; }