📄 ide.c
字号:
n = IDE_DMA_BUF_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512; if (dma_buf_rw(bm, 0) == 0) goto eot;#ifdef DEBUG_AIO printf("aio_write: sector_num=%lld n=%d\n", sector_num, n);#endif bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_write_dma_cb, bm); ide_dma_submit_check(s, ide_write_dma_cb, bm);}static void ide_sector_write_dma(IDEState *s){ s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; s->io_buffer_index = 0; s->io_buffer_size = 0; ide_dma_start(s, ide_write_dma_cb);}static void ide_device_utterly_broken(IDEState *s) { s->status |= BUSY_STAT; s->bs = NULL; /* This prevents all future commands from working. All of the * asynchronous callbacks (and ide_set_irq, as a safety measure) * check to see whether this has happened and bail if so. */}static void ide_flush_cb(void *opaque, int ret){ IDEState *s = opaque; if (!s->bs) return; /* yikes */ if (ret) { /* We are completely doomed. The IDE spec does not permit us * to return an error from a flush except via a protocol which * requires us to say where the error is and which * contemplates the guest repeating the flush attempt to * attempt flush the remaining data. We can't support that * because f(data)sync (which is what the block drivers use * eventually) doesn't report the necessary information or * give us the necessary control. So we make the disk vanish. */ ide_device_utterly_broken(s); return; } else s->status = READY_STAT; ide_set_irq(s);}static void ide_atapi_cmd_ok(IDEState *s){ s->error = 0; s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s);}static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc){#ifdef DEBUG_IDE_ATAPI printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);#endif s->error = sense_key << 4; s->status = READY_STAT | ERR_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; s->sense_key = sense_key; s->asc = asc; ide_set_irq(s);}static inline void cpu_to_ube16(uint8_t *buf, int val){ buf[0] = val >> 8; buf[1] = val;}static inline void cpu_to_ube32(uint8_t *buf, unsigned int val){ buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; buf[3] = val;}static inline int ube16_to_cpu(const uint8_t *buf){ return (buf[0] << 8) | buf[1];}static inline int ube32_to_cpu(const uint8_t *buf){ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];}static void lba_to_msf(uint8_t *buf, int lba){ lba += 150; buf[0] = (lba / 75) / 60; buf[1] = (lba / 75) % 60; buf[2] = lba % 75;}static void cd_data_to_raw(uint8_t *buf, int lba){ /* sync bytes */ buf[0] = 0x00; memset(buf + 1, 0xff, 10); buf[11] = 0x00; buf += 12; /* MSF */ lba_to_msf(buf, lba); buf[3] = 0x01; /* mode 1 data */ buf += 4; /* data */ buf += 2048; /* XXX: ECC not computed */ memset(buf, 0, 288);}static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size){ int ret; switch(sector_size) { case 2048: ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); break; case 2352: ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); if (ret < 0) return ret; cd_data_to_raw(buf, lba); break; default: ret = -EIO; break; } return ret;}static void ide_atapi_io_error(IDEState *s, int ret){ /* XXX: handle more errors */ if (ret == -ENOMEDIUM) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } else { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); }}/* The whole ATAPI transfer logic is handled in this function */static void ide_atapi_cmd_reply_end(IDEState *s){ int byte_count_limit, size, ret;#ifdef DEBUG_IDE_ATAPI printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", s->packet_transfer_size, s->elementary_transfer_size, s->io_buffer_index);#endif if (s->packet_transfer_size <= 0) { /* end of transfer */ ide_transfer_stop(s); s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s);#ifdef DEBUG_IDE_ATAPI printf("status=0x%x\n", s->status);#endif } else { /* see if a new sector must be read */ if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); if (ret < 0) { ide_transfer_stop(s); ide_atapi_io_error(s, ret); return; } s->lba++; s->io_buffer_index = 0; } if (s->elementary_transfer_size > 0) { /* there are some data left to transmit in this elementary transfer */ size = s->cd_sector_size - s->io_buffer_index; if (size > s->elementary_transfer_size) size = s->elementary_transfer_size; ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; s->io_buffer_index += size; } else { /* a new transfer is needed */ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; byte_count_limit = s->lcyl | (s->hcyl << 8);#ifdef DEBUG_IDE_ATAPI printf("byte_count_limit=%d\n", byte_count_limit);#endif if (byte_count_limit == 0xffff) byte_count_limit--; size = s->packet_transfer_size; if (size > byte_count_limit) { /* byte count limit must be even if this case */ if (byte_count_limit & 1) byte_count_limit--; size = byte_count_limit; } s->lcyl = size; s->hcyl = size >> 8; s->elementary_transfer_size = size; /* we cannot transmit more than one sector at a time */ if (s->lba != -1) { if (size > (s->cd_sector_size - s->io_buffer_index)) size = (s->cd_sector_size - s->io_buffer_index); } ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; s->io_buffer_index += size; ide_set_irq(s);#ifdef DEBUG_IDE_ATAPI printf("status=0x%x\n", s->status);#endif } }}/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size){ if (size > max_size) size = max_size; 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 (!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: ide_dma_eot(bm); 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_SECTORS / 4)) n = (IDE_DMA_BUF_SECTORS / 4); 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 inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, uint16_t profile){ uint8_t *buf_profile = buf + 12; /* start of profiles */ buf_profile += ((*index) * 4); /* start of indexed profile */ cpu_to_ube16 (buf_profile, profile); buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); /* each profile adds 4 bytes to the response */ (*index)++; buf[11] += 4; /* Additional Length */ return 4;}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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -