ide/atapi: Factor commands out
In preparation for a table of function pointers, factor each command out from ide_atapi_cmd() into its own function. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
		
							parent
							
								
									33231e0e22
								
							
						
					
					
						commit
						a60cf7e7eb
					
				
							
								
								
									
										837
									
								
								hw/ide/atapi.c
									
									
									
									
									
								
							
							
						
						
									
										837
									
								
								hw/ide/atapi.c
									
									
									
									
									
								
							@ -621,11 +621,453 @@ static void handle_get_event_status_notification(IDEState *s,
 | 
				
			|||||||
    ide_atapi_cmd_reply(s, used_len, max_len);
 | 
					    ide_atapi_cmd_reply(s, used_len, max_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_request_sense(IDEState *s, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int max_len = buf[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(buf, 0, 18);
 | 
				
			||||||
 | 
					    buf[0] = 0x70 | (1 << 7);
 | 
				
			||||||
 | 
					    buf[2] = s->sense_key;
 | 
				
			||||||
 | 
					    buf[7] = 10;
 | 
				
			||||||
 | 
					    buf[12] = s->asc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->sense_key == SENSE_UNIT_ATTENTION) {
 | 
				
			||||||
 | 
					        s->sense_key = SENSE_NONE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_atapi_cmd_reply(s, 18, max_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_inquiry(IDEState *s, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int max_len = buf[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buf[0] = 0x05; /* CD-ROM */
 | 
				
			||||||
 | 
					    buf[1] = 0x80; /* removable */
 | 
				
			||||||
 | 
					    buf[2] = 0x00; /* ISO */
 | 
				
			||||||
 | 
					    buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
 | 
				
			||||||
 | 
					    buf[4] = 31; /* additional length */
 | 
				
			||||||
 | 
					    buf[5] = 0; /* reserved */
 | 
				
			||||||
 | 
					    buf[6] = 0; /* reserved */
 | 
				
			||||||
 | 
					    buf[7] = 0; /* reserved */
 | 
				
			||||||
 | 
					    padstr8(buf + 8, 8, "QEMU");
 | 
				
			||||||
 | 
					    padstr8(buf + 16, 16, "QEMU DVD-ROM");
 | 
				
			||||||
 | 
					    padstr8(buf + 32, 4, s->version);
 | 
				
			||||||
 | 
					    ide_atapi_cmd_reply(s, 36, max_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_get_configuration(IDEState *s, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t len;
 | 
				
			||||||
 | 
					    uint8_t index = 0;
 | 
				
			||||||
 | 
					    int max_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* only feature 0 is supported */
 | 
				
			||||||
 | 
					    if (buf[2] != 0 || buf[3] != 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                            ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* XXX: could result in alignment problems in some architectures */
 | 
				
			||||||
 | 
					    max_len = ube16_to_cpu(buf + 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * XXX: avoid overflow for io_buffer if max_len is bigger than
 | 
				
			||||||
 | 
					     *      the size of that buffer (dimensioned to max number of
 | 
				
			||||||
 | 
					     *      sectors to transfer at once)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *      Only a problem if the feature/profiles grow.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (max_len > 512) {
 | 
				
			||||||
 | 
					        /* XXX: assume 1 sector */
 | 
				
			||||||
 | 
					        max_len = 512;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(buf, 0, max_len);
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * the number of sectors from the media tells us which profile
 | 
				
			||||||
 | 
					     * to use as current.  0 means there is no media
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (media_is_dvd(s)) {
 | 
				
			||||||
 | 
					        cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
 | 
				
			||||||
 | 
					    } else if (media_is_cd(s)) {
 | 
				
			||||||
 | 
					        cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buf[10] = 0x02 | 0x01; /* persistent and current */
 | 
				
			||||||
 | 
					    len = 12; /* headers: 8 + 4 */
 | 
				
			||||||
 | 
					    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
 | 
				
			||||||
 | 
					    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
 | 
				
			||||||
 | 
					    cpu_to_ube32(buf, len - 4); /* data length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_atapi_cmd_reply(s, len, max_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_mode_sense(IDEState *s, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int action, code;
 | 
				
			||||||
 | 
					    int max_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (buf[0] == GPCMD_MODE_SENSE_10) {
 | 
				
			||||||
 | 
					        max_len = ube16_to_cpu(buf + 7);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        max_len = buf[4];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    action = buf[2] >> 6;
 | 
				
			||||||
 | 
					    code = buf[2] & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(action) {
 | 
				
			||||||
 | 
					    case 0: /* current values */
 | 
				
			||||||
 | 
					        switch(code) {
 | 
				
			||||||
 | 
					        case GPMODE_R_W_ERROR_PAGE: /* error recovery */
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[0], 16 + 6);
 | 
				
			||||||
 | 
					            buf[2] = 0x70;
 | 
				
			||||||
 | 
					            buf[3] = 0;
 | 
				
			||||||
 | 
					            buf[4] = 0;
 | 
				
			||||||
 | 
					            buf[5] = 0;
 | 
				
			||||||
 | 
					            buf[6] = 0;
 | 
				
			||||||
 | 
					            buf[7] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            buf[8] = 0x01;
 | 
				
			||||||
 | 
					            buf[9] = 0x06;
 | 
				
			||||||
 | 
					            buf[10] = 0x00;
 | 
				
			||||||
 | 
					            buf[11] = 0x05;
 | 
				
			||||||
 | 
					            buf[12] = 0x00;
 | 
				
			||||||
 | 
					            buf[13] = 0x00;
 | 
				
			||||||
 | 
					            buf[14] = 0x00;
 | 
				
			||||||
 | 
					            buf[15] = 0x00;
 | 
				
			||||||
 | 
					            ide_atapi_cmd_reply(s, 16, max_len);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case GPMODE_AUDIO_CTL_PAGE:
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[0], 24 + 6);
 | 
				
			||||||
 | 
					            buf[2] = 0x70;
 | 
				
			||||||
 | 
					            buf[3] = 0;
 | 
				
			||||||
 | 
					            buf[4] = 0;
 | 
				
			||||||
 | 
					            buf[5] = 0;
 | 
				
			||||||
 | 
					            buf[6] = 0;
 | 
				
			||||||
 | 
					            buf[7] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Fill with CDROM audio volume */
 | 
				
			||||||
 | 
					            buf[17] = 0;
 | 
				
			||||||
 | 
					            buf[19] = 0;
 | 
				
			||||||
 | 
					            buf[21] = 0;
 | 
				
			||||||
 | 
					            buf[23] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ide_atapi_cmd_reply(s, 24, max_len);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case GPMODE_CAPABILITIES_PAGE:
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[0], 28 + 6);
 | 
				
			||||||
 | 
					            buf[2] = 0x70;
 | 
				
			||||||
 | 
					            buf[3] = 0;
 | 
				
			||||||
 | 
					            buf[4] = 0;
 | 
				
			||||||
 | 
					            buf[5] = 0;
 | 
				
			||||||
 | 
					            buf[6] = 0;
 | 
				
			||||||
 | 
					            buf[7] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            buf[8] = 0x2a;
 | 
				
			||||||
 | 
					            buf[9] = 0x12;
 | 
				
			||||||
 | 
					            buf[10] = 0x00;
 | 
				
			||||||
 | 
					            buf[11] = 0x00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Claim PLAY_AUDIO capability (0x01) since some Linux
 | 
				
			||||||
 | 
					               code checks for this to automount media. */
 | 
				
			||||||
 | 
					            buf[12] = 0x71;
 | 
				
			||||||
 | 
					            buf[13] = 3 << 5;
 | 
				
			||||||
 | 
					            buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
 | 
				
			||||||
 | 
					            if (bdrv_is_locked(s->bs))
 | 
				
			||||||
 | 
					                buf[6] |= 1 << 1;
 | 
				
			||||||
 | 
					            buf[15] = 0x00;
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[16], 706);
 | 
				
			||||||
 | 
					            buf[18] = 0;
 | 
				
			||||||
 | 
					            buf[19] = 2;
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[20], 512);
 | 
				
			||||||
 | 
					            cpu_to_ube16(&buf[22], 706);
 | 
				
			||||||
 | 
					            buf[24] = 0;
 | 
				
			||||||
 | 
					            buf[25] = 0;
 | 
				
			||||||
 | 
					            buf[26] = 0;
 | 
				
			||||||
 | 
					            buf[27] = 0;
 | 
				
			||||||
 | 
					            ide_atapi_cmd_reply(s, 28, max_len);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            goto error_cmd;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 1: /* changeable values */
 | 
				
			||||||
 | 
					        goto error_cmd;
 | 
				
			||||||
 | 
					    case 2: /* default values */
 | 
				
			||||||
 | 
					        goto error_cmd;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					    case 3: /* saved values */
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                            ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_cmd:
 | 
				
			||||||
 | 
					    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (bdrv_is_inserted(s->bs)) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bdrv_set_locked(s->bs, buf[4] & 1);
 | 
				
			||||||
 | 
					    ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_read(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int nb_sectors, lba;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (buf[0] == GPCMD_READ_10) {
 | 
				
			||||||
 | 
					        nb_sectors = ube16_to_cpu(buf + 7);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        nb_sectors = ube32_to_cpu(buf + 6);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lba = ube32_to_cpu(buf + 2);
 | 
				
			||||||
 | 
					    if (nb_sectors == 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_read_cd(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int nb_sectors, lba, transfer_request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
 | 
				
			||||||
 | 
					    lba = ube32_to_cpu(buf + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nb_sectors == 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    transfer_request = buf[9];
 | 
				
			||||||
 | 
					    switch(transfer_request & 0xf8) {
 | 
				
			||||||
 | 
					    case 0x00:
 | 
				
			||||||
 | 
					        /* nothing */
 | 
				
			||||||
 | 
					        ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0x10:
 | 
				
			||||||
 | 
					        /* normal read */
 | 
				
			||||||
 | 
					        ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0xf8:
 | 
				
			||||||
 | 
					        /* read all data */
 | 
				
			||||||
 | 
					        ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                            ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_seek(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned int lba;
 | 
				
			||||||
 | 
					    uint64_t total_sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_get_geometry(s->bs, &total_sectors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total_sectors >>= 2;
 | 
				
			||||||
 | 
					    if (total_sectors == 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lba = ube32_to_cpu(buf + 2);
 | 
				
			||||||
 | 
					    if (lba >= total_sectors) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int start, eject, sense, err = 0;
 | 
				
			||||||
 | 
					    start = buf[4] & 1;
 | 
				
			||||||
 | 
					    eject = (buf[4] >> 1) & 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (eject) {
 | 
				
			||||||
 | 
					        err = bdrv_eject(s->bs, !start);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (err) {
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					        ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case -EBUSY:
 | 
				
			||||||
 | 
					        sense = SENSE_NOT_READY;
 | 
				
			||||||
 | 
					        if (bdrv_is_inserted(s->bs)) {
 | 
				
			||||||
 | 
					            sense = SENSE_ILLEGAL_REQUEST;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int max_len = ube16_to_cpu(buf + 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cpu_to_ube16(buf, 0);
 | 
				
			||||||
 | 
					    /* no current LBA */
 | 
				
			||||||
 | 
					    buf[2] = 0;
 | 
				
			||||||
 | 
					    buf[3] = 0;
 | 
				
			||||||
 | 
					    buf[4] = 0;
 | 
				
			||||||
 | 
					    buf[5] = 1;
 | 
				
			||||||
 | 
					    cpu_to_ube16(buf + 6, 0);
 | 
				
			||||||
 | 
					    ide_atapi_cmd_reply(s, 8, max_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int format, msf, start_track, len;
 | 
				
			||||||
 | 
					    uint64_t total_sectors;
 | 
				
			||||||
 | 
					    int max_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_get_geometry(s->bs, &total_sectors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total_sectors >>= 2;
 | 
				
			||||||
 | 
					    if (total_sectors == 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    max_len = ube16_to_cpu(buf + 7);
 | 
				
			||||||
 | 
					    format = buf[9] >> 6;
 | 
				
			||||||
 | 
					    msf = (buf[1] >> 1) & 1;
 | 
				
			||||||
 | 
					    start_track = buf[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(format) {
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					        len = cdrom_read_toc(total_sectors, buf, msf, start_track);
 | 
				
			||||||
 | 
					        if (len < 0)
 | 
				
			||||||
 | 
					            goto error_cmd;
 | 
				
			||||||
 | 
					        ide_atapi_cmd_reply(s, len, max_len);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 1:
 | 
				
			||||||
 | 
					        /* multi session : only a single session defined */
 | 
				
			||||||
 | 
					        memset(buf, 0, 12);
 | 
				
			||||||
 | 
					        buf[1] = 0x0a;
 | 
				
			||||||
 | 
					        buf[2] = 0x01;
 | 
				
			||||||
 | 
					        buf[3] = 0x01;
 | 
				
			||||||
 | 
					        ide_atapi_cmd_reply(s, 12, max_len);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 2:
 | 
				
			||||||
 | 
					        len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
 | 
				
			||||||
 | 
					        if (len < 0)
 | 
				
			||||||
 | 
					            goto error_cmd;
 | 
				
			||||||
 | 
					        ide_atapi_cmd_reply(s, len, max_len);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					    error_cmd:
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                            ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t total_sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_get_geometry(s->bs, &total_sectors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total_sectors >>= 2;
 | 
				
			||||||
 | 
					    if (total_sectors == 0) {
 | 
				
			||||||
 | 
					        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* NOTE: it is really the number of sectors minus 1 */
 | 
				
			||||||
 | 
					    cpu_to_ube32(buf, total_sectors - 1);
 | 
				
			||||||
 | 
					    cpu_to_ube32(buf + 4, 2048);
 | 
				
			||||||
 | 
					    ide_atapi_cmd_reply(s, 8, 8);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int max_len;
 | 
				
			||||||
 | 
					    int media = buf[1];
 | 
				
			||||||
 | 
					    int format = buf[7];
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    max_len = ube16_to_cpu(buf + 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (format < 0xff) {
 | 
				
			||||||
 | 
					        if (media_is_cd(s)) {
 | 
				
			||||||
 | 
					            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                                ASC_INCOMPATIBLE_FORMAT);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        } else if (!media_present(s)) {
 | 
				
			||||||
 | 
					            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                                ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
 | 
				
			||||||
 | 
					           IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (format) {
 | 
				
			||||||
 | 
					        case 0x00 ... 0x7f:
 | 
				
			||||||
 | 
					        case 0xff:
 | 
				
			||||||
 | 
					            if (media == 0) {
 | 
				
			||||||
 | 
					                ret = ide_dvd_read_structure(s, format, buf, buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ret < 0) {
 | 
				
			||||||
 | 
					                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    ide_atapi_cmd_reply(s, ret, max_len);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            /* TODO: BD support, fall through for now */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Generic disk structures */
 | 
				
			||||||
 | 
					        case 0x80: /* TODO: AACS volume identifier */
 | 
				
			||||||
 | 
					        case 0x81: /* TODO: AACS media serial number */
 | 
				
			||||||
 | 
					        case 0x82: /* TODO: AACS media identifier */
 | 
				
			||||||
 | 
					        case 0x83: /* TODO: AACS media key block */
 | 
				
			||||||
 | 
					        case 0x90: /* TODO: List of recognized format layers */
 | 
				
			||||||
 | 
					        case 0xc0: /* TODO: Write protection status */
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
				
			||||||
 | 
					                                ASC_INV_FIELD_IN_CMD_PACKET);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_set_speed(IDEState *s, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ide_atapi_cmd_ok(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ide_atapi_cmd(IDEState *s)
 | 
					void ide_atapi_cmd(IDEState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const uint8_t *packet;
 | 
					    const uint8_t *packet;
 | 
				
			||||||
    uint8_t *buf;
 | 
					    uint8_t *buf;
 | 
				
			||||||
    int max_len;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    packet = s->io_buffer;
 | 
					    packet = s->io_buffer;
 | 
				
			||||||
    buf = s->io_buffer;
 | 
					    buf = s->io_buffer;
 | 
				
			||||||
@ -665,413 +1107,52 @@ void ide_atapi_cmd(IDEState *s)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    switch(s->io_buffer[0]) {
 | 
					    switch(s->io_buffer[0]) {
 | 
				
			||||||
    case GPCMD_TEST_UNIT_READY:
 | 
					    case GPCMD_TEST_UNIT_READY:
 | 
				
			||||||
        if (bdrv_is_inserted(s->bs)) {
 | 
					        cmd_test_unit_ready(s, buf);
 | 
				
			||||||
            ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            ide_atapi_cmd_error(s, SENSE_NOT_READY,
 | 
					 | 
				
			||||||
                                ASC_MEDIUM_NOT_PRESENT);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_MODE_SENSE_6:
 | 
					    case GPCMD_MODE_SENSE_6:
 | 
				
			||||||
    case GPCMD_MODE_SENSE_10:
 | 
					    case GPCMD_MODE_SENSE_10:
 | 
				
			||||||
        {
 | 
					        cmd_mode_sense(s, buf);
 | 
				
			||||||
            int action, code;
 | 
					 | 
				
			||||||
            if (packet[0] == GPCMD_MODE_SENSE_10)
 | 
					 | 
				
			||||||
                max_len = ube16_to_cpu(packet + 7);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                max_len = packet[4];
 | 
					 | 
				
			||||||
            action = packet[2] >> 6;
 | 
					 | 
				
			||||||
            code = packet[2] & 0x3f;
 | 
					 | 
				
			||||||
            switch(action) {
 | 
					 | 
				
			||||||
            case 0: /* current values */
 | 
					 | 
				
			||||||
                switch(code) {
 | 
					 | 
				
			||||||
                case GPMODE_R_W_ERROR_PAGE: /* error recovery */
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[0], 16 + 6);
 | 
					 | 
				
			||||||
                    buf[2] = 0x70;
 | 
					 | 
				
			||||||
                    buf[3] = 0;
 | 
					 | 
				
			||||||
                    buf[4] = 0;
 | 
					 | 
				
			||||||
                    buf[5] = 0;
 | 
					 | 
				
			||||||
                    buf[6] = 0;
 | 
					 | 
				
			||||||
                    buf[7] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    buf[8] = 0x01;
 | 
					 | 
				
			||||||
                    buf[9] = 0x06;
 | 
					 | 
				
			||||||
                    buf[10] = 0x00;
 | 
					 | 
				
			||||||
                    buf[11] = 0x05;
 | 
					 | 
				
			||||||
                    buf[12] = 0x00;
 | 
					 | 
				
			||||||
                    buf[13] = 0x00;
 | 
					 | 
				
			||||||
                    buf[14] = 0x00;
 | 
					 | 
				
			||||||
                    buf[15] = 0x00;
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_reply(s, 16, max_len);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case GPMODE_AUDIO_CTL_PAGE:
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[0], 24 + 6);
 | 
					 | 
				
			||||||
                    buf[2] = 0x70;
 | 
					 | 
				
			||||||
                    buf[3] = 0;
 | 
					 | 
				
			||||||
                    buf[4] = 0;
 | 
					 | 
				
			||||||
                    buf[5] = 0;
 | 
					 | 
				
			||||||
                    buf[6] = 0;
 | 
					 | 
				
			||||||
                    buf[7] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    /* Fill with CDROM audio volume */
 | 
					 | 
				
			||||||
                    buf[17] = 0;
 | 
					 | 
				
			||||||
                    buf[19] = 0;
 | 
					 | 
				
			||||||
                    buf[21] = 0;
 | 
					 | 
				
			||||||
                    buf[23] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_reply(s, 24, max_len);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case GPMODE_CAPABILITIES_PAGE:
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[0], 28 + 6);
 | 
					 | 
				
			||||||
                    buf[2] = 0x70;
 | 
					 | 
				
			||||||
                    buf[3] = 0;
 | 
					 | 
				
			||||||
                    buf[4] = 0;
 | 
					 | 
				
			||||||
                    buf[5] = 0;
 | 
					 | 
				
			||||||
                    buf[6] = 0;
 | 
					 | 
				
			||||||
                    buf[7] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    buf[8] = 0x2a;
 | 
					 | 
				
			||||||
                    buf[9] = 0x12;
 | 
					 | 
				
			||||||
                    buf[10] = 0x00;
 | 
					 | 
				
			||||||
                    buf[11] = 0x00;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    /* Claim PLAY_AUDIO capability (0x01) since some Linux
 | 
					 | 
				
			||||||
                       code checks for this to automount media. */
 | 
					 | 
				
			||||||
                    buf[12] = 0x71;
 | 
					 | 
				
			||||||
                    buf[13] = 3 << 5;
 | 
					 | 
				
			||||||
                    buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
 | 
					 | 
				
			||||||
                    if (bdrv_is_locked(s->bs))
 | 
					 | 
				
			||||||
                        buf[6] |= 1 << 1;
 | 
					 | 
				
			||||||
                    buf[15] = 0x00;
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[16], 706);
 | 
					 | 
				
			||||||
                    buf[18] = 0;
 | 
					 | 
				
			||||||
                    buf[19] = 2;
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[20], 512);
 | 
					 | 
				
			||||||
                    cpu_to_ube16(&buf[22], 706);
 | 
					 | 
				
			||||||
                    buf[24] = 0;
 | 
					 | 
				
			||||||
                    buf[25] = 0;
 | 
					 | 
				
			||||||
                    buf[26] = 0;
 | 
					 | 
				
			||||||
                    buf[27] = 0;
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_reply(s, 28, max_len);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                    goto error_cmd;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 1: /* changeable values */
 | 
					 | 
				
			||||||
                goto error_cmd;
 | 
					 | 
				
			||||||
            case 2: /* default values */
 | 
					 | 
				
			||||||
                goto error_cmd;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
            case 3: /* saved values */
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                    ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_REQUEST_SENSE:
 | 
					    case GPCMD_REQUEST_SENSE:
 | 
				
			||||||
        max_len = packet[4];
 | 
					        cmd_request_sense(s, buf);
 | 
				
			||||||
        memset(buf, 0, 18);
 | 
					 | 
				
			||||||
        buf[0] = 0x70 | (1 << 7);
 | 
					 | 
				
			||||||
        buf[2] = s->sense_key;
 | 
					 | 
				
			||||||
        buf[7] = 10;
 | 
					 | 
				
			||||||
        buf[12] = s->asc;
 | 
					 | 
				
			||||||
        if (s->sense_key == SENSE_UNIT_ATTENTION)
 | 
					 | 
				
			||||||
            s->sense_key = SENSE_NONE;
 | 
					 | 
				
			||||||
        ide_atapi_cmd_reply(s, 18, max_len);
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
 | 
					    case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
 | 
				
			||||||
        bdrv_set_locked(s->bs, packet[4] & 1);
 | 
					        cmd_prevent_allow_medium_removal(s, buf);
 | 
				
			||||||
        ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_READ_10:
 | 
					    case GPCMD_READ_10:
 | 
				
			||||||
    case GPCMD_READ_12:
 | 
					    case GPCMD_READ_12:
 | 
				
			||||||
        {
 | 
					        cmd_read(s, buf);
 | 
				
			||||||
            int nb_sectors, lba;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (packet[0] == GPCMD_READ_10)
 | 
					 | 
				
			||||||
                nb_sectors = ube16_to_cpu(packet + 7);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                nb_sectors = ube32_to_cpu(packet + 6);
 | 
					 | 
				
			||||||
            lba = ube32_to_cpu(packet + 2);
 | 
					 | 
				
			||||||
            if (nb_sectors == 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_READ_CD:
 | 
					    case GPCMD_READ_CD:
 | 
				
			||||||
        {
 | 
					        cmd_read_cd(s, buf);
 | 
				
			||||||
            int nb_sectors, lba, transfer_request;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8];
 | 
					 | 
				
			||||||
            lba = ube32_to_cpu(packet + 2);
 | 
					 | 
				
			||||||
            if (nb_sectors == 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            transfer_request = packet[9];
 | 
					 | 
				
			||||||
            switch(transfer_request & 0xf8) {
 | 
					 | 
				
			||||||
            case 0x00:
 | 
					 | 
				
			||||||
                /* nothing */
 | 
					 | 
				
			||||||
                ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 0x10:
 | 
					 | 
				
			||||||
                /* normal read */
 | 
					 | 
				
			||||||
                ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 0xf8:
 | 
					 | 
				
			||||||
                /* read all data */
 | 
					 | 
				
			||||||
                ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                    ASC_INV_FIELD_IN_CMD_PACKET);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_SEEK:
 | 
					    case GPCMD_SEEK:
 | 
				
			||||||
        {
 | 
					        cmd_seek(s, buf);
 | 
				
			||||||
            unsigned int lba;
 | 
					 | 
				
			||||||
            uint64_t total_sectors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bdrv_get_geometry(s->bs, &total_sectors);
 | 
					 | 
				
			||||||
            total_sectors >>= 2;
 | 
					 | 
				
			||||||
            if (total_sectors == 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_NOT_READY,
 | 
					 | 
				
			||||||
                                    ASC_MEDIUM_NOT_PRESENT);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            lba = ube32_to_cpu(packet + 2);
 | 
					 | 
				
			||||||
            if (lba >= total_sectors) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                    ASC_LOGICAL_BLOCK_OOR);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_START_STOP_UNIT:
 | 
					    case GPCMD_START_STOP_UNIT:
 | 
				
			||||||
        {
 | 
					        cmd_start_stop_unit(s, buf);
 | 
				
			||||||
            int start, eject, sense, err = 0;
 | 
					 | 
				
			||||||
            start = packet[4] & 1;
 | 
					 | 
				
			||||||
            eject = (packet[4] >> 1) & 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (eject) {
 | 
					 | 
				
			||||||
                err = bdrv_eject(s->bs, !start);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            switch (err) {
 | 
					 | 
				
			||||||
            case 0:
 | 
					 | 
				
			||||||
                ide_atapi_cmd_ok(s);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case -EBUSY:
 | 
					 | 
				
			||||||
                sense = SENSE_NOT_READY;
 | 
					 | 
				
			||||||
                if (bdrv_is_inserted(s->bs)) {
 | 
					 | 
				
			||||||
                    sense = SENSE_ILLEGAL_REQUEST;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, sense,
 | 
					 | 
				
			||||||
                                    ASC_MEDIA_REMOVAL_PREVENTED);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_NOT_READY,
 | 
					 | 
				
			||||||
                                    ASC_MEDIUM_NOT_PRESENT);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_MECHANISM_STATUS:
 | 
					    case GPCMD_MECHANISM_STATUS:
 | 
				
			||||||
        {
 | 
					        cmd_mechanism_status(s, buf);
 | 
				
			||||||
            max_len = ube16_to_cpu(packet + 8);
 | 
					 | 
				
			||||||
            cpu_to_ube16(buf, 0);
 | 
					 | 
				
			||||||
            /* no current LBA */
 | 
					 | 
				
			||||||
            buf[2] = 0;
 | 
					 | 
				
			||||||
            buf[3] = 0;
 | 
					 | 
				
			||||||
            buf[4] = 0;
 | 
					 | 
				
			||||||
            buf[5] = 1;
 | 
					 | 
				
			||||||
            cpu_to_ube16(buf + 6, 0);
 | 
					 | 
				
			||||||
            ide_atapi_cmd_reply(s, 8, max_len);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_READ_TOC_PMA_ATIP:
 | 
					    case GPCMD_READ_TOC_PMA_ATIP:
 | 
				
			||||||
        {
 | 
					        cmd_read_toc_pma_atip(s, buf);
 | 
				
			||||||
            int format, msf, start_track, len;
 | 
					 | 
				
			||||||
            uint64_t total_sectors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bdrv_get_geometry(s->bs, &total_sectors);
 | 
					 | 
				
			||||||
            total_sectors >>= 2;
 | 
					 | 
				
			||||||
            if (total_sectors == 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_NOT_READY,
 | 
					 | 
				
			||||||
                                    ASC_MEDIUM_NOT_PRESENT);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            max_len = ube16_to_cpu(packet + 7);
 | 
					 | 
				
			||||||
            format = packet[9] >> 6;
 | 
					 | 
				
			||||||
            msf = (packet[1] >> 1) & 1;
 | 
					 | 
				
			||||||
            start_track = packet[6];
 | 
					 | 
				
			||||||
            switch(format) {
 | 
					 | 
				
			||||||
            case 0:
 | 
					 | 
				
			||||||
                len = cdrom_read_toc(total_sectors, buf, msf, start_track);
 | 
					 | 
				
			||||||
                if (len < 0)
 | 
					 | 
				
			||||||
                    goto error_cmd;
 | 
					 | 
				
			||||||
                ide_atapi_cmd_reply(s, len, max_len);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 1:
 | 
					 | 
				
			||||||
                /* multi session : only a single session defined */
 | 
					 | 
				
			||||||
                memset(buf, 0, 12);
 | 
					 | 
				
			||||||
                buf[1] = 0x0a;
 | 
					 | 
				
			||||||
                buf[2] = 0x01;
 | 
					 | 
				
			||||||
                buf[3] = 0x01;
 | 
					 | 
				
			||||||
                ide_atapi_cmd_reply(s, 12, max_len);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 2:
 | 
					 | 
				
			||||||
                len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
 | 
					 | 
				
			||||||
                if (len < 0)
 | 
					 | 
				
			||||||
                    goto error_cmd;
 | 
					 | 
				
			||||||
                ide_atapi_cmd_reply(s, len, max_len);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
            error_cmd:
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                    ASC_INV_FIELD_IN_CMD_PACKET);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_READ_CDVD_CAPACITY:
 | 
					    case GPCMD_READ_CDVD_CAPACITY:
 | 
				
			||||||
        {
 | 
					        cmd_read_cdvd_capacity(s, buf);
 | 
				
			||||||
            uint64_t total_sectors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bdrv_get_geometry(s->bs, &total_sectors);
 | 
					 | 
				
			||||||
            total_sectors >>= 2;
 | 
					 | 
				
			||||||
            if (total_sectors == 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_NOT_READY,
 | 
					 | 
				
			||||||
                                    ASC_MEDIUM_NOT_PRESENT);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            /* NOTE: it is really the number of sectors minus 1 */
 | 
					 | 
				
			||||||
            cpu_to_ube32(buf, total_sectors - 1);
 | 
					 | 
				
			||||||
            cpu_to_ube32(buf + 4, 2048);
 | 
					 | 
				
			||||||
            ide_atapi_cmd_reply(s, 8, 8);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_READ_DVD_STRUCTURE:
 | 
					    case GPCMD_READ_DVD_STRUCTURE:
 | 
				
			||||||
        {
 | 
					        cmd_read_dvd_structure(s, buf);
 | 
				
			||||||
            int media = packet[1];
 | 
					 | 
				
			||||||
            int format = packet[7];
 | 
					 | 
				
			||||||
            int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            max_len = ube16_to_cpu(packet + 8);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (format < 0xff) {
 | 
					 | 
				
			||||||
                if (media_is_cd(s)) {
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                        ASC_INCOMPATIBLE_FORMAT);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                } else if (!media_present(s)) {
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                        ASC_INV_FIELD_IN_CMD_PACKET);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
 | 
					 | 
				
			||||||
                   IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            switch (format) {
 | 
					 | 
				
			||||||
                case 0x00 ... 0x7f:
 | 
					 | 
				
			||||||
                case 0xff:
 | 
					 | 
				
			||||||
                    if (media == 0) {
 | 
					 | 
				
			||||||
                        ret = ide_dvd_read_structure(s, format, packet, buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (ret < 0)
 | 
					 | 
				
			||||||
                            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                            ide_atapi_cmd_reply(s, ret, max_len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    /* TODO: BD support, fall through for now */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                /* Generic disk structures */
 | 
					 | 
				
			||||||
                case 0x80: /* TODO: AACS volume identifier */
 | 
					 | 
				
			||||||
                case 0x81: /* TODO: AACS media serial number */
 | 
					 | 
				
			||||||
                case 0x82: /* TODO: AACS media identifier */
 | 
					 | 
				
			||||||
                case 0x83: /* TODO: AACS media key block */
 | 
					 | 
				
			||||||
                case 0x90: /* TODO: List of recognized format layers */
 | 
					 | 
				
			||||||
                case 0xc0: /* TODO: Write protection status */
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                        ASC_INV_FIELD_IN_CMD_PACKET);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_SET_SPEED:
 | 
					    case GPCMD_SET_SPEED:
 | 
				
			||||||
        ide_atapi_cmd_ok(s);
 | 
					        cmd_set_speed(s, buf);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_INQUIRY:
 | 
					    case GPCMD_INQUIRY:
 | 
				
			||||||
        max_len = packet[4];
 | 
					        cmd_inquiry(s, buf);
 | 
				
			||||||
        buf[0] = 0x05; /* CD-ROM */
 | 
					 | 
				
			||||||
        buf[1] = 0x80; /* removable */
 | 
					 | 
				
			||||||
        buf[2] = 0x00; /* ISO */
 | 
					 | 
				
			||||||
        buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
 | 
					 | 
				
			||||||
        buf[4] = 31; /* additional length */
 | 
					 | 
				
			||||||
        buf[5] = 0; /* reserved */
 | 
					 | 
				
			||||||
        buf[6] = 0; /* reserved */
 | 
					 | 
				
			||||||
        buf[7] = 0; /* reserved */
 | 
					 | 
				
			||||||
        padstr8(buf + 8, 8, "QEMU");
 | 
					 | 
				
			||||||
        padstr8(buf + 16, 16, "QEMU DVD-ROM");
 | 
					 | 
				
			||||||
        padstr8(buf + 32, 4, s->version);
 | 
					 | 
				
			||||||
        ide_atapi_cmd_reply(s, 36, max_len);
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case GPCMD_GET_CONFIGURATION:
 | 
					    case GPCMD_GET_CONFIGURATION:
 | 
				
			||||||
        {
 | 
					        cmd_get_configuration(s, buf);
 | 
				
			||||||
            uint32_t len;
 | 
					        break;
 | 
				
			||||||
            uint8_t index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /* only feature 0 is supported */
 | 
					 | 
				
			||||||
            if (packet[2] != 0 || packet[3] != 0) {
 | 
					 | 
				
			||||||
                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
 | 
					 | 
				
			||||||
                                    ASC_INV_FIELD_IN_CMD_PACKET);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /* XXX: could result in alignment problems in some architectures */
 | 
					 | 
				
			||||||
            max_len = ube16_to_cpu(packet + 7);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /*
 | 
					 | 
				
			||||||
             * XXX: avoid overflow for io_buffer if max_len is bigger than
 | 
					 | 
				
			||||||
             *      the size of that buffer (dimensioned to max number of
 | 
					 | 
				
			||||||
             *      sectors to transfer at once)
 | 
					 | 
				
			||||||
             *
 | 
					 | 
				
			||||||
             *      Only a problem if the feature/profiles grow.
 | 
					 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            if (max_len > 512) /* XXX: assume 1 sector */
 | 
					 | 
				
			||||||
                max_len = 512;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            memset(buf, 0, max_len);
 | 
					 | 
				
			||||||
            /*
 | 
					 | 
				
			||||||
             * the number of sectors from the media tells us which profile
 | 
					 | 
				
			||||||
             * to use as current.  0 means there is no media
 | 
					 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            if (media_is_dvd(s))
 | 
					 | 
				
			||||||
                cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
 | 
					 | 
				
			||||||
            else if (media_is_cd(s))
 | 
					 | 
				
			||||||
                cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            buf[10] = 0x02 | 0x01; /* persistent and current */
 | 
					 | 
				
			||||||
            len = 12; /* headers: 8 + 4 */
 | 
					 | 
				
			||||||
            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
 | 
					 | 
				
			||||||
            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
 | 
					 | 
				
			||||||
            cpu_to_ube32(buf, len - 4); /* data length */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            ide_atapi_cmd_reply(s, len, max_len);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
 | 
					    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
 | 
				
			||||||
        handle_get_event_status_notification(s, buf, packet);
 | 
					        handle_get_event_status_notification(s, buf, packet);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user