void ide_exec_cmd(IDEBus *bus, uint32_t val)

{

    uint16_t *identify_data;

    IDEState *s;

    int n;

    int lba48 = 0;



#if defined(DEBUG_IDE)

    printf("ide: CMD=%02x\n", val);

#endif

    s = idebus_active_if(bus);

    /* ignore commands to non existent slave */

    if (s != bus->ifs && !s->bs)

        return;



    /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */

    if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)

        return;



    if (!ide_cmd_permitted(s, val)) {

        goto abort_cmd;

    }



    if (ide_cmd_table[val].handler != NULL) {

        bool complete;



        s->status = READY_STAT | BUSY_STAT;

        s->error = 0;



        complete = ide_cmd_table[val].handler(s, val);

        if (complete) {

            s->status &= ~BUSY_STAT;

            assert(!!s->error == !!(s->status & ERR_STAT));



            if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {

                s->status |= SEEK_STAT;

            }



            ide_set_irq(s->bus);

        }



        return;

    }



    switch(val) {

    case WIN_SETMULT:

        if (s->drive_kind == IDE_CFATA && s->nsector == 0) {

            /* Disable Read and Write Multiple */

            s->mult_sectors = 0;

            s->status = READY_STAT | SEEK_STAT;

        } else if ((s->nsector & 0xff) != 0 &&

            ((s->nsector & 0xff) > MAX_MULT_SECTORS ||

             (s->nsector & (s->nsector - 1)) != 0)) {

            ide_abort_command(s);

        } else {

            s->mult_sectors = s->nsector & 0xff;

            s->status = READY_STAT | SEEK_STAT;

        }

        ide_set_irq(s->bus);

        break;



    case WIN_VERIFY_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_VERIFY:

    case WIN_VERIFY_ONCE:

        /* do sector number check ? */

	ide_cmd_lba48_transform(s, lba48);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_READ_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_READ:

    case WIN_READ_ONCE:

        if (s->drive_kind == IDE_CD) {

            ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */

            goto abort_cmd;

        }

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->req_nb_sectors = 1;

        ide_sector_read(s);

        break;



    case WIN_WRITE_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_WRITE:

    case WIN_WRITE_ONCE:

    case CFA_WRITE_SECT_WO_ERASE:

    case WIN_WRITE_VERIFY:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = 1;

        ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_MULTREAD_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_MULTREAD:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->req_nb_sectors = s->mult_sectors;

        ide_sector_read(s);

        break;



    case WIN_MULTWRITE_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_MULTWRITE:

    case CFA_WRITE_MULTI_WO_ERASE:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = s->mult_sectors;

        n = s->nsector;

        if (n > s->req_nb_sectors)

            n = s->req_nb_sectors;

        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_READDMA_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_READDMA:

    case WIN_READDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_sector_start_dma(s, IDE_DMA_READ);

        break;



    case WIN_WRITEDMA_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_WRITEDMA:

    case WIN_WRITEDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_sector_start_dma(s, IDE_DMA_WRITE);

        s->media_changed = 1;

        break;



    case WIN_READ_NATIVE_MAX_EXT:

        lba48 = 1;

        /* fall through */

    case WIN_READ_NATIVE_MAX:

        /* Refuse if no sectors are addressable (e.g. medium not inserted) */

        if (s->nb_sectors == 0) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_set_sector(s, s->nb_sectors - 1);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_CHECKPOWERMODE1:

    case WIN_CHECKPOWERMODE2:

        s->error = 0;

        s->nsector = 0xff; /* device active or idle */

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case WIN_SETFEATURES:

        if (!s->bs)

            goto abort_cmd;

        /* XXX: valid for CDROM ? */

        switch(s->feature) {

        case 0x02: /* write cache enable */

            bdrv_set_enable_write_cache(s->bs, true);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

        case 0x82: /* write cache disable */

            bdrv_set_enable_write_cache(s->bs, false);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | 1);

            ide_flush_cache(s);

            break;

        case 0xcc: /* reverting to power-on defaults enable */

        case 0x66: /* reverting to power-on defaults disable */

        case 0xaa: /* read look-ahead enable */

        case 0x55: /* read look-ahead disable */

        case 0x05: /* set advanced power management mode */

        case 0x85: /* disable advanced power management mode */

        case 0x69: /* NOP */

        case 0x67: /* NOP */

        case 0x96: /* NOP */

        case 0x9a: /* NOP */

        case 0x42: /* enable Automatic Acoustic Mode */

        case 0xc2: /* disable Automatic Acoustic Mode */

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

        case 0x03: { /* set transfer mode */

		uint8_t val = s->nsector & 0x07;

		identify_data = (uint16_t *)s->identify_data;



		switch (s->nsector >> 3) {

		case 0x00: /* pio default */

		case 0x01: /* pio mode */

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

                case 0x02: /* sigle word dma mode*/

			put_le16(identify_data + 62,0x07 | (1 << (val + 8)));

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x04: /* mdma mode */

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07 | (1 << (val + 8)));

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x08: /* udma mode */

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f | (1 << (val + 8)));

			break;

		default:

			goto abort_cmd;

		}

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

	}

        default:

            goto abort_cmd;

        }

        break;

    case WIN_FLUSH_CACHE:

    case WIN_FLUSH_CACHE_EXT:

        ide_flush_cache(s);

        break;

    case WIN_SEEK:

        /* XXX: Check that seek is within bounds */

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

        /* ATAPI commands */

    case WIN_PIDENTIFY:

        ide_atapi_identify(s);

        s->status = READY_STAT | SEEK_STAT;

        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);

        ide_set_irq(s->bus);

        break;

    case WIN_DIAGNOSE:

        ide_set_signature(s);

        if (s->drive_kind == IDE_CD)

            s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet

                            * devices to return a clear status register

                            * with READY_STAT *not* set. */

        else

            s->status = READY_STAT | SEEK_STAT;

        s->error = 0x01; /* Device 0 passed, Device 1 passed or not

                          * present.

                          */

        ide_set_irq(s->bus);

        break;

    case WIN_DEVICE_RESET:

        ide_set_signature(s);

        s->status = 0x00; /* NOTE: READY is _not_ set */

        s->error = 0x01;

        break;

    case WIN_PACKETCMD:

        /* overlapping commands not supported */

        if (s->feature & 0x02)

            goto abort_cmd;

        s->status = READY_STAT | SEEK_STAT;

        s->atapi_dma = s->feature & 1;

        s->nsector = 1;

        ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,

                           ide_atapi_cmd);

        break;

    /* CF-ATA commands */

    case CFA_REQ_EXT_ERROR_CODE:

        s->error = 0x09;    /* miscellaneous error */

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case CFA_ERASE_SECTORS:

    case CFA_WEAR_LEVEL:

#if 0

    /* This one has the same ID as CFA_WEAR_LEVEL and is required for

       Windows 8 to work with AHCI */

    case WIN_SECURITY_FREEZE_LOCK:

#endif

        if (val == CFA_WEAR_LEVEL)

            s->nsector = 0;

        if (val == CFA_ERASE_SECTORS)

            s->media_changed = 1;

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case CFA_TRANSLATE_SECTOR:

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        memset(s->io_buffer, 0, 0x200);

        s->io_buffer[0x00] = s->hcyl;			/* Cyl MSB */

        s->io_buffer[0x01] = s->lcyl;			/* Cyl LSB */

        s->io_buffer[0x02] = s->select;			/* Head */

        s->io_buffer[0x03] = s->sector;			/* Sector */

        s->io_buffer[0x04] = ide_get_sector(s) >> 16;	/* LBA MSB */

        s->io_buffer[0x05] = ide_get_sector(s) >> 8;	/* LBA */

        s->io_buffer[0x06] = ide_get_sector(s) >> 0;	/* LBA LSB */

        s->io_buffer[0x13] = 0x00;				/* Erase flag */

        s->io_buffer[0x18] = 0x00;				/* Hot count */

        s->io_buffer[0x19] = 0x00;				/* Hot count */

        s->io_buffer[0x1a] = 0x01;				/* Hot count */

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        ide_set_irq(s->bus);

        break;

    case CFA_ACCESS_METADATA_STORAGE:

        switch (s->feature) {

        case 0x02:	/* Inquiry Metadata Storage */

            ide_cfata_metadata_inquiry(s);

            break;

        case 0x03:	/* Read Metadata Storage */

            ide_cfata_metadata_read(s);

            break;

        case 0x04:	/* Write Metadata Storage */

            ide_cfata_metadata_write(s);

            break;

        default:

            goto abort_cmd;

        }

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        s->status = 0x00; /* NOTE: READY is _not_ set */

        ide_set_irq(s->bus);

        break;

    case IBM_SENSE_CONDITION:

        switch (s->feature) {

        case 0x01:  /* sense temperature in device */

            s->nsector = 0x50;      /* +20 C */

            break;

        default:

            goto abort_cmd;

        }

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_SMART:

	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)

		goto abort_cmd;

	if (!s->smart_enabled && s->feature != SMART_ENABLE)

		goto abort_cmd;

	switch (s->feature) {

	case SMART_DISABLE:

		s->smart_enabled = 0;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_ENABLE:

		s->smart_enabled = 1;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_ATTR_AUTOSAVE:

		switch (s->sector) {

		case 0x00:

		s->smart_autosave = 0;

		break;

		case 0xf1:

		s->smart_autosave = 1;

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_STATUS:

		if (!s->smart_errors) {

		s->hcyl = 0xc2;

		s->lcyl = 0x4f;

		} else {

		s->hcyl = 0x2c;

		s->lcyl = 0xf4;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_READ_THRESH:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; /* smart struct version */

		for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {

		s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];

		s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];

		}

		for (n=0; n<511; n++) /* checksum */

		s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_READ_DATA:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; /* smart struct version */

		for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {

		    int i;

		    for(i = 0; i < 11; i++) {

			s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];

		    }

		}

		s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);

		if (s->smart_selftest_count == 0) {

		s->io_buffer[363] = 0;

		} else {

		s->io_buffer[363] =

			s->smart_selftest_data[3 + 

					   (s->smart_selftest_count - 1) *

					   24];

		}

		s->io_buffer[364] = 0x20; 

		s->io_buffer[365] = 0x01; 

		/* offline data collection capacity: execute + self-test*/

		s->io_buffer[367] = (1<<4 | 1<<3 | 1); 

		s->io_buffer[368] = 0x03; /* smart capability (1) */

		s->io_buffer[369] = 0x00; /* smart capability (2) */

		s->io_buffer[370] = 0x01; /* error logging supported */

		s->io_buffer[372] = 0x02; /* minutes for poll short test */

		s->io_buffer[373] = 0x36; /* minutes for poll ext test */

		s->io_buffer[374] = 0x01; /* minutes for poll conveyance */



		for (n=0; n<511; n++) 

		s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_READ_LOG:

		switch (s->sector) {

		case 0x01: /* summary smart error log */

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		s->io_buffer[1] = 0x00; /* no error entries */

		s->io_buffer[452] = s->smart_errors & 0xff;

		s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;



		for (n=0; n<511; n++)

			s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		case 0x06: /* smart self test log */

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		if (s->smart_selftest_count == 0) {

			s->io_buffer[508] = 0;

		} else {

			s->io_buffer[508] = s->smart_selftest_count;

			for (n=2; n<506; n++) 

			s->io_buffer[n] = s->smart_selftest_data[n];

		}

		for (n=0; n<511; n++)

			s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_EXECUTE_OFFLINE:

		switch (s->sector) {

		case 0: /* off-line routine */

		case 1: /* short self test */

		case 2: /* extended self test */

		s->smart_selftest_count++;

		if(s->smart_selftest_count > 21)

			s->smart_selftest_count = 0;

		n = 2 + (s->smart_selftest_count - 1) * 24;

		s->smart_selftest_data[n] = s->sector;

		s->smart_selftest_data[n+1] = 0x00; /* OK and finished */

		s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */

		s->smart_selftest_data[n+3] = 0x12; /* hour count msb */

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

		default:

		goto abort_cmd;

		}

		break;

	default:

		goto abort_cmd;

	}

	break;

    default:

        /* should not be reachable */

    abort_cmd:

        ide_abort_command(s);

        ide_set_irq(s->bus);

        break;

    }

}

void ide_exec_cmd(IDEBus *bus, uint32_t val)

{

    uint16_t *identify_data;

    IDEState *s;

    int n;

    int lba48 = 0;



#if defined(DEBUG_IDE)

    printf("ide: CMD=%02x\n", val);

#endif

    s = idebus_active_if(bus);

    

    if (s != bus->ifs && !s->bs)

        return;



    

    if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)

        return;



    if (!ide_cmd_permitted(s, val)) {

        goto abort_cmd;

    }



    if (ide_cmd_table[val].handler != NULL) {

        bool complete;



        s->status = READY_STAT | BUSY_STAT;

        s->error = 0;



        complete = ide_cmd_table[val].handler(s, val);

        if (complete) {

            s->status &= ~BUSY_STAT;

            assert(!!s->error == !!(s->status & ERR_STAT));



            if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {

                s->status |= SEEK_STAT;

            }



            ide_set_irq(s->bus);

        }



        return;

    }



    switch(val) {

    case WIN_SETMULT:

        if (s->drive_kind == IDE_CFATA && s->nsector == 0) {

            

            s->mult_sectors = 0;

            s->status = READY_STAT | SEEK_STAT;

        } else if ((s->nsector & 0xff) != 0 &&

            ((s->nsector & 0xff) > MAX_MULT_SECTORS ||

             (s->nsector & (s->nsector - 1)) != 0)) {

            ide_abort_command(s);

        } else {

            s->mult_sectors = s->nsector & 0xff;

            s->status = READY_STAT | SEEK_STAT;

        }

        ide_set_irq(s->bus);

        break;



    case WIN_VERIFY_EXT:

        lba48 = 1;

        

    case WIN_VERIFY:

    case WIN_VERIFY_ONCE:

        

	ide_cmd_lba48_transform(s, lba48);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_READ_EXT:

        lba48 = 1;

        

    case WIN_READ:

    case WIN_READ_ONCE:

        if (s->drive_kind == IDE_CD) {

            ide_set_signature(s); 

            goto abort_cmd;

        }

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->req_nb_sectors = 1;

        ide_sector_read(s);

        break;



    case WIN_WRITE_EXT:

        lba48 = 1;

        

    case WIN_WRITE:

    case WIN_WRITE_ONCE:

    case CFA_WRITE_SECT_WO_ERASE:

    case WIN_WRITE_VERIFY:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = 1;

        ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_MULTREAD_EXT:

        lba48 = 1;

        

    case WIN_MULTREAD:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->req_nb_sectors = s->mult_sectors;

        ide_sector_read(s);

        break;



    case WIN_MULTWRITE_EXT:

        lba48 = 1;

        

    case WIN_MULTWRITE:

    case CFA_WRITE_MULTI_WO_ERASE:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = s->mult_sectors;

        n = s->nsector;

        if (n > s->req_nb_sectors)

            n = s->req_nb_sectors;

        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_READDMA_EXT:

        lba48 = 1;

        

    case WIN_READDMA:

    case WIN_READDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_sector_start_dma(s, IDE_DMA_READ);

        break;



    case WIN_WRITEDMA_EXT:

        lba48 = 1;

        

    case WIN_WRITEDMA:

    case WIN_WRITEDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_sector_start_dma(s, IDE_DMA_WRITE);

        s->media_changed = 1;

        break;



    case WIN_READ_NATIVE_MAX_EXT:

        lba48 = 1;

        

    case WIN_READ_NATIVE_MAX:

        

        if (s->nb_sectors == 0) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, lba48);

        ide_set_sector(s, s->nb_sectors - 1);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_CHECKPOWERMODE1:

    case WIN_CHECKPOWERMODE2:

        s->error = 0;

        s->nsector = 0xff; 

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case WIN_SETFEATURES:

        if (!s->bs)

            goto abort_cmd;

        

        switch(s->feature) {

        case 0x02: 

            bdrv_set_enable_write_cache(s->bs, true);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

        case 0x82: 

            bdrv_set_enable_write_cache(s->bs, false);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | 1);

            ide_flush_cache(s);

            break;

        case 0xcc: 

        case 0x66: 

        case 0xaa: 

        case 0x55: 

        case 0x05: 

        case 0x85: 

        case 0x69: 

        case 0x67: 

        case 0x96: 

        case 0x9a: 

        case 0x42: 

        case 0xc2: 

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

        case 0x03: { 

		uint8_t val = s->nsector & 0x07;

		identify_data = (uint16_t *)s->identify_data;



		switch (s->nsector >> 3) {

		case 0x00: 

		case 0x01: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

                case 0x02: 

			put_le16(identify_data + 62,0x07 | (1 << (val + 8)));

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x04: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07 | (1 << (val + 8)));

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x08: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f | (1 << (val + 8)));

			break;

		default:

			goto abort_cmd;

		}

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->bus);

            break;

	}

        default:

            goto abort_cmd;

        }

        break;

    case WIN_FLUSH_CACHE:

    case WIN_FLUSH_CACHE_EXT:

        ide_flush_cache(s);

        break;

    case WIN_SEEK:

        

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

        

    case WIN_PIDENTIFY:

        ide_atapi_identify(s);

        s->status = READY_STAT | SEEK_STAT;

        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);

        ide_set_irq(s->bus);

        break;

    case WIN_DIAGNOSE:

        ide_set_signature(s);

        if (s->drive_kind == IDE_CD)

            s->status = 0; 





        else

            s->status = READY_STAT | SEEK_STAT;

        s->error = 0x01; 





        ide_set_irq(s->bus);

        break;

    case WIN_DEVICE_RESET:

        ide_set_signature(s);

        s->status = 0x00; 

        s->error = 0x01;

        break;

    case WIN_PACKETCMD:

        

        if (s->feature & 0x02)

            goto abort_cmd;

        s->status = READY_STAT | SEEK_STAT;

        s->atapi_dma = s->feature & 1;

        s->nsector = 1;

        ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,

                           ide_atapi_cmd);

        break;

    

    case CFA_REQ_EXT_ERROR_CODE:

        s->error = 0x09;    

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case CFA_ERASE_SECTORS:

    case CFA_WEAR_LEVEL:

#if 0

    



    case WIN_SECURITY_FREEZE_LOCK:

#endif

        if (val == CFA_WEAR_LEVEL)

            s->nsector = 0;

        if (val == CFA_ERASE_SECTORS)

            s->media_changed = 1;

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;

    case CFA_TRANSLATE_SECTOR:

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        memset(s->io_buffer, 0, 0x200);

        s->io_buffer[0x00] = s->hcyl;			

        s->io_buffer[0x01] = s->lcyl;			

        s->io_buffer[0x02] = s->select;			

        s->io_buffer[0x03] = s->sector;			

        s->io_buffer[0x04] = ide_get_sector(s) >> 16;	

        s->io_buffer[0x05] = ide_get_sector(s) >> 8;	

        s->io_buffer[0x06] = ide_get_sector(s) >> 0;	

        s->io_buffer[0x13] = 0x00;				

        s->io_buffer[0x18] = 0x00;				

        s->io_buffer[0x19] = 0x00;				

        s->io_buffer[0x1a] = 0x01;				

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        ide_set_irq(s->bus);

        break;

    case CFA_ACCESS_METADATA_STORAGE:

        switch (s->feature) {

        case 0x02:	

            ide_cfata_metadata_inquiry(s);

            break;

        case 0x03:	

            ide_cfata_metadata_read(s);

            break;

        case 0x04:	

            ide_cfata_metadata_write(s);

            break;

        default:

            goto abort_cmd;

        }

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        s->status = 0x00; 

        ide_set_irq(s->bus);

        break;

    case IBM_SENSE_CONDITION:

        switch (s->feature) {

        case 0x01:  

            s->nsector = 0x50;      

            break;

        default:

            goto abort_cmd;

        }

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->bus);

        break;



    case WIN_SMART:

	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)

		goto abort_cmd;

	if (!s->smart_enabled && s->feature != SMART_ENABLE)

		goto abort_cmd;

	switch (s->feature) {

	case SMART_DISABLE:

		s->smart_enabled = 0;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_ENABLE:

		s->smart_enabled = 1;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_ATTR_AUTOSAVE:

		switch (s->sector) {

		case 0x00:

		s->smart_autosave = 0;

		break;

		case 0xf1:

		s->smart_autosave = 1;

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_STATUS:

		if (!s->smart_errors) {

		s->hcyl = 0xc2;

		s->lcyl = 0x4f;

		} else {

		s->hcyl = 0x2c;

		s->lcyl = 0xf4;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

	case SMART_READ_THRESH:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; 

		for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {

		s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];

		s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];

		}

		for (n=0; n<511; n++) 

		s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_READ_DATA:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; 

		for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {

		    int i;

		    for(i = 0; i < 11; i++) {

			s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];

		    }

		}

		s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);

		if (s->smart_selftest_count == 0) {

		s->io_buffer[363] = 0;

		} else {

		s->io_buffer[363] =

			s->smart_selftest_data[3 + 

					   (s->smart_selftest_count - 1) *

					   24];

		}

		s->io_buffer[364] = 0x20; 

		s->io_buffer[365] = 0x01; 

		

		s->io_buffer[367] = (1<<4 | 1<<3 | 1); 

		s->io_buffer[368] = 0x03; 

		s->io_buffer[369] = 0x00; 

		s->io_buffer[370] = 0x01; 

		s->io_buffer[372] = 0x02; 

		s->io_buffer[373] = 0x36; 

		s->io_buffer[374] = 0x01; 



		for (n=0; n<511; n++) 

		s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_READ_LOG:

		switch (s->sector) {

		case 0x01: 

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		s->io_buffer[1] = 0x00; 

		s->io_buffer[452] = s->smart_errors & 0xff;

		s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;



		for (n=0; n<511; n++)

			s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		case 0x06: 

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		if (s->smart_selftest_count == 0) {

			s->io_buffer[508] = 0;

		} else {

			s->io_buffer[508] = s->smart_selftest_count;

			for (n=2; n<506; n++) 

			s->io_buffer[n] = s->smart_selftest_data[n];

		}

		for (n=0; n<511; n++)

			s->io_buffer[511] += s->io_buffer[n];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->bus);

		break;

	case SMART_EXECUTE_OFFLINE:

		switch (s->sector) {

		case 0: 

		case 1: 

		case 2: 

		s->smart_selftest_count++;

		if(s->smart_selftest_count > 21)

			s->smart_selftest_count = 0;

		n = 2 + (s->smart_selftest_count - 1) * 24;

		s->smart_selftest_data[n] = s->sector;

		s->smart_selftest_data[n+1] = 0x00; 

		s->smart_selftest_data[n+2] = 0x34; 

		s->smart_selftest_data[n+3] = 0x12; 

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->bus);

		break;

		default:

		goto abort_cmd;

		}

		break;

	default:

		goto abort_cmd;

	}

	break;

    default:

        

    abort_cmd:

        ide_abort_command(s);

        ide_set_irq(s->bus);

        break;

    }

}

    case WIN_VERIFY_EXT:         lba48 = 1;     case WIN_VERIFY:     case WIN_VERIFY_ONCE: 	ide_cmd_lba48_transform(s, lba48);         s->status = READY_STAT | SEEK_STAT;         ide_set_irq(s->bus);         break;
void FUNC_0(IDEBus *VAR_0, uint32_t VAR_1)

{

    uint16_t *identify_data;

    IDEState *s;

    int VAR_2;

    int VAR_3 = 0;



#if defined(DEBUG_IDE)

    printf("ide: CMD=%02x\VAR_2", VAR_1);

#endif

    s = idebus_active_if(VAR_0);

    

    if (s != VAR_0->ifs && !s->bs)

        return;



    

    if ((s->status & (BUSY_STAT|DRQ_STAT)) && VAR_1 != WIN_DEVICE_RESET)

        return;



    if (!ide_cmd_permitted(s, VAR_1)) {

        goto abort_cmd;

    }



    if (ide_cmd_table[VAR_1].handler != NULL) {

        bool complete;



        s->status = READY_STAT | BUSY_STAT;

        s->error = 0;



        complete = ide_cmd_table[VAR_1].handler(s, VAR_1);

        if (complete) {

            s->status &= ~BUSY_STAT;

            assert(!!s->error == !!(s->status & ERR_STAT));



            if ((ide_cmd_table[VAR_1].flags & SET_DSC) && !s->error) {

                s->status |= SEEK_STAT;

            }



            ide_set_irq(s->VAR_0);

        }



        return;

    }



    switch(VAR_1) {

    case WIN_SETMULT:

        if (s->drive_kind == IDE_CFATA && s->nsector == 0) {

            

            s->mult_sectors = 0;

            s->status = READY_STAT | SEEK_STAT;

        } else if ((s->nsector & 0xff) != 0 &&

            ((s->nsector & 0xff) > MAX_MULT_SECTORS ||

             (s->nsector & (s->nsector - 1)) != 0)) {

            ide_abort_command(s);

        } else {

            s->mult_sectors = s->nsector & 0xff;

            s->status = READY_STAT | SEEK_STAT;

        }

        ide_set_irq(s->VAR_0);

        break;



    case WIN_VERIFY_EXT:

        VAR_3 = 1;

        

    case WIN_VERIFY:

    case WIN_VERIFY_ONCE:

        

	ide_cmd_lba48_transform(s, VAR_3);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;



    case WIN_READ_EXT:

        VAR_3 = 1;

        

    case WIN_READ:

    case WIN_READ_ONCE:

        if (s->drive_kind == IDE_CD) {

            ide_set_signature(s); 

            goto abort_cmd;

        }

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        s->req_nb_sectors = 1;

        ide_sector_read(s);

        break;



    case WIN_WRITE_EXT:

        VAR_3 = 1;

        

    case WIN_WRITE:

    case WIN_WRITE_ONCE:

    case CFA_WRITE_SECT_WO_ERASE:

    case WIN_WRITE_VERIFY:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = 1;

        ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_MULTREAD_EXT:

        VAR_3 = 1;

        

    case WIN_MULTREAD:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        s->req_nb_sectors = s->mult_sectors;

        ide_sector_read(s);

        break;



    case WIN_MULTWRITE_EXT:

        VAR_3 = 1;

        

    case WIN_MULTWRITE:

    case CFA_WRITE_MULTI_WO_ERASE:

        if (!s->bs) {

            goto abort_cmd;

        }

        if (!s->mult_sectors) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        s->error = 0;

        s->status = SEEK_STAT | READY_STAT;

        s->req_nb_sectors = s->mult_sectors;

        VAR_2 = s->nsector;

        if (VAR_2 > s->req_nb_sectors)

            VAR_2 = s->req_nb_sectors;

        ide_transfer_start(s, s->io_buffer, 512 * VAR_2, ide_sector_write);

        s->media_changed = 1;

        break;



    case WIN_READDMA_EXT:

        VAR_3 = 1;

        

    case WIN_READDMA:

    case WIN_READDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        ide_sector_start_dma(s, IDE_DMA_READ);

        break;



    case WIN_WRITEDMA_EXT:

        VAR_3 = 1;

        

    case WIN_WRITEDMA:

    case WIN_WRITEDMA_ONCE:

        if (!s->bs) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        ide_sector_start_dma(s, IDE_DMA_WRITE);

        s->media_changed = 1;

        break;



    case WIN_READ_NATIVE_MAX_EXT:

        VAR_3 = 1;

        

    case WIN_READ_NATIVE_MAX:

        

        if (s->nb_sectors == 0) {

            goto abort_cmd;

        }

	ide_cmd_lba48_transform(s, VAR_3);

        ide_set_sector(s, s->nb_sectors - 1);

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;



    case WIN_CHECKPOWERMODE1:

    case WIN_CHECKPOWERMODE2:

        s->error = 0;

        s->nsector = 0xff; 

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;

    case WIN_SETFEATURES:

        if (!s->bs)

            goto abort_cmd;

        

        switch(s->feature) {

        case 0x02: 

            bdrv_set_enable_write_cache(s->bs, true);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->VAR_0);

            break;

        case 0x82: 

            bdrv_set_enable_write_cache(s->bs, false);

            identify_data = (uint16_t *)s->identify_data;

            put_le16(identify_data + 85, (1 << 14) | 1);

            ide_flush_cache(s);

            break;

        case 0xcc: 

        case 0x66: 

        case 0xaa: 

        case 0x55: 

        case 0x05: 

        case 0x85: 

        case 0x69: 

        case 0x67: 

        case 0x96: 

        case 0x9a: 

        case 0x42: 

        case 0xc2: 

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->VAR_0);

            break;

        case 0x03: { 

		uint8_t VAR_1 = s->nsector & 0x07;

		identify_data = (uint16_t *)s->identify_data;



		switch (s->nsector >> 3) {

		case 0x00: 

		case 0x01: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

                case 0x02: 

			put_le16(identify_data + 62,0x07 | (1 << (VAR_1 + 8)));

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x04: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07 | (1 << (VAR_1 + 8)));

			put_le16(identify_data + 88,0x3f);

			break;

		case 0x08: 

			put_le16(identify_data + 62,0x07);

			put_le16(identify_data + 63,0x07);

			put_le16(identify_data + 88,0x3f | (1 << (VAR_1 + 8)));

			break;

		default:

			goto abort_cmd;

		}

            s->status = READY_STAT | SEEK_STAT;

            ide_set_irq(s->VAR_0);

            break;

	}

        default:

            goto abort_cmd;

        }

        break;

    case WIN_FLUSH_CACHE:

    case WIN_FLUSH_CACHE_EXT:

        ide_flush_cache(s);

        break;

    case WIN_SEEK:

        

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;

        

    case WIN_PIDENTIFY:

        ide_atapi_identify(s);

        s->status = READY_STAT | SEEK_STAT;

        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);

        ide_set_irq(s->VAR_0);

        break;

    case WIN_DIAGNOSE:

        ide_set_signature(s);

        if (s->drive_kind == IDE_CD)

            s->status = 0; 





        else

            s->status = READY_STAT | SEEK_STAT;

        s->error = 0x01; 





        ide_set_irq(s->VAR_0);

        break;

    case WIN_DEVICE_RESET:

        ide_set_signature(s);

        s->status = 0x00; 

        s->error = 0x01;

        break;

    case WIN_PACKETCMD:

        

        if (s->feature & 0x02)

            goto abort_cmd;

        s->status = READY_STAT | SEEK_STAT;

        s->atapi_dma = s->feature & 1;

        s->nsector = 1;

        ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,

                           ide_atapi_cmd);

        break;

    

    case CFA_REQ_EXT_ERROR_CODE:

        s->error = 0x09;    

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;

    case CFA_ERASE_SECTORS:

    case CFA_WEAR_LEVEL:

#if 0

    



    case WIN_SECURITY_FREEZE_LOCK:

#endif

        if (VAR_1 == CFA_WEAR_LEVEL)

            s->nsector = 0;

        if (VAR_1 == CFA_ERASE_SECTORS)

            s->media_changed = 1;

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;

    case CFA_TRANSLATE_SECTOR:

        s->error = 0x00;

        s->status = READY_STAT | SEEK_STAT;

        memset(s->io_buffer, 0, 0x200);

        s->io_buffer[0x00] = s->hcyl;			

        s->io_buffer[0x01] = s->lcyl;			

        s->io_buffer[0x02] = s->select;			

        s->io_buffer[0x03] = s->sector;			

        s->io_buffer[0x04] = ide_get_sector(s) >> 16;	

        s->io_buffer[0x05] = ide_get_sector(s) >> 8;	

        s->io_buffer[0x06] = ide_get_sector(s) >> 0;	

        s->io_buffer[0x13] = 0x00;				

        s->io_buffer[0x18] = 0x00;				

        s->io_buffer[0x19] = 0x00;				

        s->io_buffer[0x1a] = 0x01;				

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        ide_set_irq(s->VAR_0);

        break;

    case CFA_ACCESS_METADATA_STORAGE:

        switch (s->feature) {

        case 0x02:	

            ide_cfata_metadata_inquiry(s);

            break;

        case 0x03:	

            ide_cfata_metadata_read(s);

            break;

        case 0x04:	

            ide_cfata_metadata_write(s);

            break;

        default:

            goto abort_cmd;

        }

        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

        s->status = 0x00; 

        ide_set_irq(s->VAR_0);

        break;

    case IBM_SENSE_CONDITION:

        switch (s->feature) {

        case 0x01:  

            s->nsector = 0x50;      

            break;

        default:

            goto abort_cmd;

        }

        s->status = READY_STAT | SEEK_STAT;

        ide_set_irq(s->VAR_0);

        break;



    case WIN_SMART:

	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)

		goto abort_cmd;

	if (!s->smart_enabled && s->feature != SMART_ENABLE)

		goto abort_cmd;

	switch (s->feature) {

	case SMART_DISABLE:

		s->smart_enabled = 0;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->VAR_0);

		break;

	case SMART_ENABLE:

		s->smart_enabled = 1;

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->VAR_0);

		break;

	case SMART_ATTR_AUTOSAVE:

		switch (s->sector) {

		case 0x00:

		s->smart_autosave = 0;

		break;

		case 0xf1:

		s->smart_autosave = 1;

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->VAR_0);

		break;

	case SMART_STATUS:

		if (!s->smart_errors) {

		s->hcyl = 0xc2;

		s->lcyl = 0x4f;

		} else {

		s->hcyl = 0x2c;

		s->lcyl = 0xf4;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->VAR_0);

		break;

	case SMART_READ_THRESH:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; 

		for (VAR_2 = 0; VAR_2 < ARRAY_SIZE(smart_attributes); VAR_2++) {

		s->io_buffer[2+0+(VAR_2*12)] = smart_attributes[VAR_2][0];

		s->io_buffer[2+1+(VAR_2*12)] = smart_attributes[VAR_2][11];

		}

		for (VAR_2=0; VAR_2<511; VAR_2++) 

		s->io_buffer[511] += s->io_buffer[VAR_2];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->VAR_0);

		break;

	case SMART_READ_DATA:

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01; 

		for (VAR_2 = 0; VAR_2 < ARRAY_SIZE(smart_attributes); VAR_2++) {

		    int i;

		    for(i = 0; i < 11; i++) {

			s->io_buffer[2+i+(VAR_2*12)] = smart_attributes[VAR_2][i];

		    }

		}

		s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);

		if (s->smart_selftest_count == 0) {

		s->io_buffer[363] = 0;

		} else {

		s->io_buffer[363] =

			s->smart_selftest_data[3 + 

					   (s->smart_selftest_count - 1) *

					   24];

		}

		s->io_buffer[364] = 0x20; 

		s->io_buffer[365] = 0x01; 

		

		s->io_buffer[367] = (1<<4 | 1<<3 | 1); 

		s->io_buffer[368] = 0x03; 

		s->io_buffer[369] = 0x00; 

		s->io_buffer[370] = 0x01; 

		s->io_buffer[372] = 0x02; 

		s->io_buffer[373] = 0x36; 

		s->io_buffer[374] = 0x01; 



		for (VAR_2=0; VAR_2<511; VAR_2++) 

		s->io_buffer[511] += s->io_buffer[VAR_2];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->VAR_0);

		break;

	case SMART_READ_LOG:

		switch (s->sector) {

		case 0x01: 

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		s->io_buffer[1] = 0x00; 

		s->io_buffer[452] = s->smart_errors & 0xff;

		s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;



		for (VAR_2=0; VAR_2<511; VAR_2++)

			s->io_buffer[511] += s->io_buffer[VAR_2];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		case 0x06: 

		memset(s->io_buffer, 0, 0x200);

		s->io_buffer[0] = 0x01;

		if (s->smart_selftest_count == 0) {

			s->io_buffer[508] = 0;

		} else {

			s->io_buffer[508] = s->smart_selftest_count;

			for (VAR_2=2; VAR_2<506; VAR_2++) 

			s->io_buffer[VAR_2] = s->smart_selftest_data[VAR_2];

		}

		for (VAR_2=0; VAR_2<511; VAR_2++)

			s->io_buffer[511] += s->io_buffer[VAR_2];

		s->io_buffer[511] = 0x100 - s->io_buffer[511];

		break;

		default:

		goto abort_cmd;

		}

		s->status = READY_STAT | SEEK_STAT;

		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);

		ide_set_irq(s->VAR_0);

		break;

	case SMART_EXECUTE_OFFLINE:

		switch (s->sector) {

		case 0: 

		case 1: 

		case 2: 

		s->smart_selftest_count++;

		if(s->smart_selftest_count > 21)

			s->smart_selftest_count = 0;

		VAR_2 = 2 + (s->smart_selftest_count - 1) * 24;

		s->smart_selftest_data[VAR_2] = s->sector;

		s->smart_selftest_data[VAR_2+1] = 0x00; 

		s->smart_selftest_data[VAR_2+2] = 0x34; 

		s->smart_selftest_data[VAR_2+3] = 0x12; 

		s->status = READY_STAT | SEEK_STAT;

		ide_set_irq(s->VAR_0);

		break;

		default:

		goto abort_cmd;

		}

		break;

	default:

		goto abort_cmd;

	}

	break;

    default:

        

    abort_cmd:

        ide_abort_command(s);

        ide_set_irq(s->VAR_0);

        break;

    }

}

void FUNC_0(IDEBus *VAR_0, uint32_t VAR_1)
{ uint16_t *identify_data; IDEState *s; int VAR_2; int VAR_3 = 0; #if defined(DEBUG_IDE)
printf("ide: CMD=%02x\VAR_2", VAR_1); #endif
s = idebus_active_if(VAR_0); if (s != VAR_0->ifs && !s->bs)
return; if ((s->status & (BUSY_STAT|DRQ_STAT)) && VAR_1 != WIN_DEVICE_RESET)
return; if (!ide_cmd_permitted(s, VAR_1)) { goto abort_cmd; } if (ide_cmd_table[VAR_1].handler != NULL) { bool complete; s->status = READY_STAT | BUSY_STAT; s->error = 0; complete = ide_cmd_table[VAR_1].handler(s, VAR_1); if (complete) { s->status &= ~BUSY_STAT; assert(!!s->error == !!(s->status & ERR_STAT)); if ((ide_cmd_table[VAR_1].flags & SET_DSC) && !s->error) { s->status |= SEEK_STAT; } ide_set_irq(s->VAR_0); } return; } switch(VAR_1) { case WIN_SETMULT:
if (s->drive_kind == IDE_CFATA && s->nsector == 0) { s->mult_sectors = 0; s->status = READY_STAT | SEEK_STAT; } else if ((s->nsector & 0xff) != 0 && ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
(s->nsector & (s->nsector - 1)) != 0)) { ide_abort_command(s); } else { s->mult_sectors = s->nsector & 0xff; s->status = READY_STAT | SEEK_STAT; } ide_set_irq(s->VAR_0); break; case WIN_VERIFY_EXT:
VAR_3 = 1; case WIN_VERIFY:
case WIN_VERIFY_ONCE:
ide_cmd_lba48_transform(s, VAR_3); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case WIN_READ_EXT:
VAR_3 = 1; case WIN_READ:
case WIN_READ_ONCE:
if (s->drive_kind == IDE_CD) { ide_set_signature(s); goto abort_cmd; } if (!s->bs) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); s->req_nb_sectors = 1; ide_sector_read(s); break; case WIN_WRITE_EXT:
VAR_3 = 1; case WIN_WRITE:
case WIN_WRITE_ONCE:
case CFA_WRITE_SECT_WO_ERASE:
case WIN_WRITE_VERIFY:
if (!s->bs) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); s->error = 0; s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = 1; ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); s->media_changed = 1; break; case WIN_MULTREAD_EXT:
VAR_3 = 1; case WIN_MULTREAD:
if (!s->bs) { goto abort_cmd; } if (!s->mult_sectors) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); s->req_nb_sectors = s->mult_sectors; ide_sector_read(s); break; case WIN_MULTWRITE_EXT:
VAR_3 = 1; case WIN_MULTWRITE:
case CFA_WRITE_MULTI_WO_ERASE:
if (!s->bs) { goto abort_cmd; } if (!s->mult_sectors) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); s->error = 0; s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = s->mult_sectors; VAR_2 = s->nsector; if (VAR_2 > s->req_nb_sectors)
VAR_2 = s->req_nb_sectors; ide_transfer_start(s, s->io_buffer, 512 * VAR_2, ide_sector_write); s->media_changed = 1; break; case WIN_READDMA_EXT:
VAR_3 = 1; case WIN_READDMA:
case WIN_READDMA_ONCE:
if (!s->bs) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); ide_sector_start_dma(s, IDE_DMA_READ); break; case WIN_WRITEDMA_EXT:
VAR_3 = 1; case WIN_WRITEDMA:
case WIN_WRITEDMA_ONCE:
if (!s->bs) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); ide_sector_start_dma(s, IDE_DMA_WRITE); s->media_changed = 1; break; case WIN_READ_NATIVE_MAX_EXT:
VAR_3 = 1; case WIN_READ_NATIVE_MAX:
if (s->nb_sectors == 0) { goto abort_cmd; } ide_cmd_lba48_transform(s, VAR_3); ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case WIN_CHECKPOWERMODE1:
case WIN_CHECKPOWERMODE2:
s->error = 0; s->nsector = 0xff; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case WIN_SETFEATURES:
if (!s->bs)
goto abort_cmd; switch(s->feature) { case 0x02:
bdrv_set_enable_write_cache(s->bs, true); identify_data = (uint16_t *)s->identify_data; put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case 0x82:
bdrv_set_enable_write_cache(s->bs, false); identify_data = (uint16_t *)s->identify_data; put_le16(identify_data + 85, (1 << 14) | 1); ide_flush_cache(s); break; case 0xcc:
case 0x66:
case 0xaa:
case 0x55:
case 0x05:
case 0x85:
case 0x69:
case 0x67:
case 0x96:
case 0x9a:
case 0x42:
case 0xc2:
s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case 0x03: { uint8_t VAR_1 = s->nsector & 0x07; identify_data = (uint16_t *)s->identify_data; switch (s->nsector >> 3) { case 0x00:
case 0x01:
put_le16(identify_data + 62,0x07); put_le16(identify_data + 63,0x07); put_le16(identify_data + 88,0x3f); break; case 0x02:
put_le16(identify_data + 62,0x07 | (1 << (VAR_1 + 8))); put_le16(identify_data + 63,0x07); put_le16(identify_data + 88,0x3f); break; case 0x04:
put_le16(identify_data + 62,0x07); put_le16(identify_data + 63,0x07 | (1 << (VAR_1 + 8))); put_le16(identify_data + 88,0x3f); break; case 0x08:
put_le16(identify_data + 62,0x07); put_le16(identify_data + 63,0x07); put_le16(identify_data + 88,0x3f | (1 << (VAR_1 + 8))); break; default:
goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; } default:
goto abort_cmd; } break; case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
ide_flush_cache(s); break; case WIN_SEEK:
s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case WIN_PIDENTIFY:
ide_atapi_identify(s); s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); ide_set_irq(s->VAR_0); break; case WIN_DIAGNOSE:
ide_set_signature(s); if (s->drive_kind == IDE_CD)
s->status = 0; else
s->status = READY_STAT | SEEK_STAT; s->error = 0x01; ide_set_irq(s->VAR_0); break; case WIN_DEVICE_RESET:
ide_set_signature(s); s->status = 0x00; s->error = 0x01; break; case WIN_PACKETCMD:
if (s->feature & 0x02)
goto abort_cmd; s->status = READY_STAT | SEEK_STAT; s->atapi_dma = s->feature & 1; s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
ide_atapi_cmd); break; case CFA_REQ_EXT_ERROR_CODE:
s->error = 0x09; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case CFA_ERASE_SECTORS:
case CFA_WEAR_LEVEL:
#if 0
case WIN_SECURITY_FREEZE_LOCK:
#endif
if (VAR_1 == CFA_WEAR_LEVEL)
s->nsector = 0; if (VAR_1 == CFA_ERASE_SECTORS)
s->media_changed = 1; s->error = 0x00; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case CFA_TRANSLATE_SECTOR:
s->error = 0x00; s->status = READY_STAT | SEEK_STAT; memset(s->io_buffer, 0, 0x200); s->io_buffer[0x00] = s->hcyl; s->io_buffer[0x01] = s->lcyl; s->io_buffer[0x02] = s->select; s->io_buffer[0x03] = s->sector; s->io_buffer[0x04] = ide_get_sector(s) >> 16; s->io_buffer[0x05] = ide_get_sector(s) >> 8; s->io_buffer[0x06] = ide_get_sector(s) >> 0; s->io_buffer[0x13] = 0x00; s->io_buffer[0x18] = 0x00; s->io_buffer[0x19] = 0x00; s->io_buffer[0x1a] = 0x01; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->VAR_0); break; case CFA_ACCESS_METADATA_STORAGE:
switch (s->feature) { case 0x02:
ide_cfata_metadata_inquiry(s); break; case 0x03:
ide_cfata_metadata_read(s); break; case 0x04:
ide_cfata_metadata_write(s); break; default:
goto abort_cmd; } ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); s->status = 0x00; ide_set_irq(s->VAR_0); break; case IBM_SENSE_CONDITION:
switch (s->feature) { case 0x01:
s->nsector = 0x50; break; default:
goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case WIN_SMART:
if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
goto abort_cmd; if (!s->smart_enabled && s->feature != SMART_ENABLE)
goto abort_cmd; switch (s->feature) { case SMART_DISABLE:
s->smart_enabled = 0; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case SMART_ENABLE:
s->smart_enabled = 1; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case SMART_ATTR_AUTOSAVE:
switch (s->sector) { case 0x00:
s->smart_autosave = 0; break; case 0xf1:
s->smart_autosave = 1; break; default:
goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case SMART_STATUS:
if (!s->smart_errors) { s->hcyl = 0xc2; s->lcyl = 0x4f; } else { s->hcyl = 0x2c; s->lcyl = 0xf4; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; case SMART_READ_THRESH:
memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; for (VAR_2 = 0; VAR_2 < ARRAY_SIZE(smart_attributes); VAR_2++) { s->io_buffer[2+0+(VAR_2*12)] = smart_attributes[VAR_2][0]; s->io_buffer[2+1+(VAR_2*12)] = smart_attributes[VAR_2][11]; } for (VAR_2=0; VAR_2<511; VAR_2++) s->io_buffer[511] += s->io_buffer[VAR_2]; s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->VAR_0); break; case SMART_READ_DATA:
memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; for (VAR_2 = 0; VAR_2 < ARRAY_SIZE(smart_attributes); VAR_2++) { int i; for(i = 0; i < 11; i++) { s->io_buffer[2+i+(VAR_2*12)] = smart_attributes[VAR_2][i]; } } s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00); if (s->smart_selftest_count == 0) { s->io_buffer[363] = 0; } else { s->io_buffer[363] =
s->smart_selftest_data[3 +
(s->smart_selftest_count - 1) *
24]; } s->io_buffer[364] = 0x20; s->io_buffer[365] = 0x01; s->io_buffer[367] = (1<<4 | 1<<3 | 1); s->io_buffer[368] = 0x03; s->io_buffer[369] = 0x00; s->io_buffer[370] = 0x01; s->io_buffer[372] = 0x02; s->io_buffer[373] = 0x36; s->io_buffer[374] = 0x01; for (VAR_2=0; VAR_2<511; VAR_2++) s->io_buffer[511] += s->io_buffer[VAR_2]; s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->VAR_0); break; case SMART_READ_LOG:
switch (s->sector) { case 0x01:
memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; s->io_buffer[1] = 0x00; s->io_buffer[452] = s->smart_errors & 0xff; s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; for (VAR_2=0; VAR_2<511; VAR_2++) s->io_buffer[511] += s->io_buffer[VAR_2]; s->io_buffer[511] = 0x100 - s->io_buffer[511]; break; case 0x06:
memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; if (s->smart_selftest_count == 0) { s->io_buffer[508] = 0; } else { s->io_buffer[508] = s->smart_selftest_count; for (VAR_2=2; VAR_2<506; VAR_2++) s->io_buffer[VAR_2] = s->smart_selftest_data[VAR_2]; } for (VAR_2=0; VAR_2<511; VAR_2++) s->io_buffer[511] += s->io_buffer[VAR_2]; s->io_buffer[511] = 0x100 - s->io_buffer[511]; break; default:
goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->VAR_0); break; case SMART_EXECUTE_OFFLINE:
switch (s->sector) { case 0:
case 1:
case 2:
s->smart_selftest_count++; if(s->smart_selftest_count > 21)
s->smart_selftest_count = 0; VAR_2 = 2 + (s->smart_selftest_count - 1) * 24; s->smart_selftest_data[VAR_2] = s->sector; s->smart_selftest_data[VAR_2+1] = 0x00; s->smart_selftest_data[VAR_2+2] = 0x34; s->smart_selftest_data[VAR_2+3] = 0x12; s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->VAR_0); break; default:
goto abort_cmd; } break; default:
goto abort_cmd; } break; default:
abort_cmd:
ide_abort_command(s); ide_set_irq(s->VAR_0); break; } }