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;
}
Exemple #2
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);
}
Exemple #4
0
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;
}