📄 ide.c
字号:
s->lba = -1; /* no sector read */ s->packet_transfer_size = size; s->io_buffer_size = size; /* dma: send the reply data as one chunk */ s->elementary_transfer_size = 0; s->io_buffer_index = 0; if (s->atapi_dma) { s->status = READY_STAT | DRQ_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb); } else { s->status = READY_STAT; ide_atapi_cmd_reply_end(s); }}/* start a CD-CDROM read command */static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, int sector_size){ s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; s->elementary_transfer_size = 0; s->io_buffer_index = sector_size; s->cd_sector_size = sector_size; s->status = READY_STAT; ide_atapi_cmd_reply_end(s);}/* ATAPI DMA support *//* XXX: handle read errors */static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret){ BMDMAState *bm = opaque; IDEState *s = bm->ide_if; int data_offset, n; if (!s->bs) return; /* yikes */ if (ret < 0) { ide_atapi_io_error(s, ret); goto eot; } if (s->io_buffer_size > 0) { /* * For a cdrom read sector command (s->lba != -1), * adjust the lba for the next s->io_buffer_size chunk * and dma the current chunk. * For a command != read (s->lba == -1), just transfer * the reply data. */ if (s->lba != -1) { if (s->cd_sector_size == 2352) { n = 1; cd_data_to_raw(s->io_buffer, s->lba); } else { n = s->io_buffer_size >> 11; } s->lba += n; } s->packet_transfer_size -= s->io_buffer_size; if (dma_buf_rw(bm, 1) == 0) goto eot; } if (s->packet_transfer_size <= 0) { s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); eot: bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; bm->dma_cb = NULL; bm->ide_if = NULL; bm->aiocb = NULL; return; } s->io_buffer_index = 0; if (s->cd_sector_size == 2352) { n = 1; s->io_buffer_size = s->cd_sector_size; data_offset = 16; } else { n = s->packet_transfer_size >> 11; if (n > (IDE_DMA_BUF_SIZE / 2048)) n = (IDE_DMA_BUF_SIZE / 2048); s->io_buffer_size = n * 2048; data_offset = 0; }#ifdef DEBUG_AIO printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);#endif bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, s->io_buffer + data_offset, n * 4, ide_atapi_cmd_read_dma_cb, bm); if (!bm->aiocb) { /* Note: media not present is the most likely case */ ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); goto eot; }}/* start a CD-CDROM read command with DMA *//* XXX: test if DMA is available */static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, int sector_size){ s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; s->io_buffer_index = 0; s->io_buffer_size = 0; s->cd_sector_size = sector_size; /* XXX: check if BUSY_STAT should be set */ s->status = READY_STAT | DRQ_STAT | BUSY_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb);}static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, int sector_size){#ifdef DEBUG_IDE_ATAPI printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", lba, nb_sectors);#endif if (s->atapi_dma) { ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); } else { ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); }}static void ide_atapi_cmd(IDEState *s){ const uint8_t *packet; uint8_t *buf; int max_len; packet = s->io_buffer; buf = s->io_buffer;#ifdef DEBUG_IDE_ATAPI { int i; printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); for(i = 0; i < ATAPI_PACKET_SIZE; i++) { printf(" %02x", packet[i]); } printf("\n"); }#endif switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: if (bdrv_is_inserted(s->bs)) { if (s->is_cdrom && s->sense_key == SENSE_NOT_READY) { ide_atapi_cmd_error(s, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED); break; } ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); xenstore_check_new_media_present(1000); } break; case GPCMD_MODE_SENSE_10: { int action, code; max_len = ube16_to_cpu(packet + 7); action = packet[2] >> 6; code = packet[2] & 0x3f; switch(action) { case 0: /* current values */ switch(code) { case 0x01: /* 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 0x2a: 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; buf[12] = 0x70; 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; case GPCMD_REQUEST_SENSE: max_len = packet[4]; memset(buf, 0, 18); buf[0] = 0x70 | (1 << 7); buf[2] = s->sense_key; buf[7] = 10; buf[12] = s->asc; ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: if (bdrv_is_inserted(s->bs)) { bdrv_set_locked(s->bs, packet[4] & 1); ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; case GPCMD_READ_10: case GPCMD_READ_12: { 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; case GPCMD_READ_CD: { 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; case GPCMD_SEEK: { int lba; int64_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; case GPCMD_START_STOP_UNIT: { int start, eject; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; if (eject && !start) { /* eject the disk */ bdrv_eject(s->bs, 1); } else if (eject && start) { /* close the tray */ bdrv_eject(s->bs, 0); } ide_atapi_cmd_ok(s); } break; case GPCMD_MECHANISM_STATUS: { 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; case GPCMD_READ_TOC_PMA_ATIP: { int format, msf, start_track, len; int64_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; case GPCMD_READ_CDVD_CAPACITY: { int64_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; case GPCMD_INQUIRY: max_len = packet[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; /* additionnal length */ buf[5] = 0; /* reserved */ buf[6] = 0; /* reserved */ buf[7] = 0; /* reserved */ padstr8(buf + 8, 8, "QEMU"); padstr8(buf + 16, 16, "QEMU CD-ROM");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -