Revision 66c6ef76 hw/ide.c
b/hw/ide.c | ||
---|---|---|
943 | 943 |
memset(buf, 0, 288); |
944 | 944 |
} |
945 | 945 |
|
946 |
static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
|
946 |
static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
|
947 | 947 |
int sector_size) |
948 | 948 |
{ |
949 |
int ret; |
|
950 |
|
|
949 | 951 |
switch(sector_size) { |
950 | 952 |
case 2048: |
951 |
bdrv_read(bs, (int64_t)lba << 2, buf, 4); |
|
953 |
ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4);
|
|
952 | 954 |
break; |
953 | 955 |
case 2352: |
954 |
bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); |
|
956 |
ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); |
|
957 |
if (ret < 0) |
|
958 |
return ret; |
|
955 | 959 |
cd_data_to_raw(buf, lba); |
956 | 960 |
break; |
957 | 961 |
default: |
962 |
ret = -EIO; |
|
958 | 963 |
break; |
959 | 964 |
} |
965 |
return ret; |
|
966 |
} |
|
967 |
|
|
968 |
static void ide_atapi_io_error(IDEState *s, int ret) |
|
969 |
{ |
|
970 |
/* XXX: handle more errors */ |
|
971 |
if (ret == -ENOMEDIUM) { |
|
972 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
973 |
ASC_MEDIUM_NOT_PRESENT); |
|
974 |
} else { |
|
975 |
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
|
976 |
ASC_LOGICAL_BLOCK_OOR); |
|
977 |
} |
|
960 | 978 |
} |
961 | 979 |
|
962 | 980 |
/* The whole ATAPI transfer logic is handled in this function */ |
963 | 981 |
static void ide_atapi_cmd_reply_end(IDEState *s) |
964 | 982 |
{ |
965 |
int byte_count_limit, size; |
|
983 |
int byte_count_limit, size, ret;
|
|
966 | 984 |
#ifdef DEBUG_IDE_ATAPI |
967 | 985 |
printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", |
968 | 986 |
s->packet_transfer_size, |
... | ... | |
981 | 999 |
} else { |
982 | 1000 |
/* see if a new sector must be read */ |
983 | 1001 |
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { |
984 |
cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); |
|
1002 |
ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); |
|
1003 |
if (ret < 0) { |
|
1004 |
ide_transfer_stop(s); |
|
1005 |
ide_atapi_io_error(s, ret); |
|
1006 |
return; |
|
1007 |
} |
|
985 | 1008 |
s->lba++; |
986 | 1009 |
s->io_buffer_index = 0; |
987 | 1010 |
} |
... | ... | |
1070 | 1093 |
IDEState *s = bm->ide_if; |
1071 | 1094 |
int data_offset, n; |
1072 | 1095 |
|
1096 |
if (ret < 0) { |
|
1097 |
ide_atapi_io_error(s, ret); |
|
1098 |
goto eot; |
|
1099 |
} |
|
1100 |
|
|
1073 | 1101 |
if (s->io_buffer_size > 0) { |
1074 | 1102 |
if (s->cd_sector_size == 2352) { |
1075 | 1103 |
n = 1; |
... | ... | |
1114 | 1142 |
bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, |
1115 | 1143 |
s->io_buffer + data_offset, n * 4, |
1116 | 1144 |
ide_atapi_cmd_read_dma_cb, bm); |
1145 |
if (!bm->aiocb) { |
|
1146 |
/* Note: media not present is the most likely case */ |
|
1147 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
1148 |
ASC_MEDIUM_NOT_PRESENT); |
|
1149 |
goto eot; |
|
1150 |
} |
|
1117 | 1151 |
} |
1118 | 1152 |
|
1119 | 1153 |
/* start a CD-CDROM read command with DMA */ |
... | ... | |
1270 | 1304 |
{ |
1271 | 1305 |
int nb_sectors, lba; |
1272 | 1306 |
|
1273 |
if (!bdrv_is_inserted(s->bs)) { |
|
1274 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
1275 |
ASC_MEDIUM_NOT_PRESENT); |
|
1276 |
break; |
|
1277 |
} |
|
1278 | 1307 |
if (packet[0] == GPCMD_READ_10) |
1279 | 1308 |
nb_sectors = ube16_to_cpu(packet + 7); |
1280 | 1309 |
else |
... | ... | |
1284 | 1313 |
ide_atapi_cmd_ok(s); |
1285 | 1314 |
break; |
1286 | 1315 |
} |
1287 |
if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { |
|
1288 |
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
|
1289 |
ASC_LOGICAL_BLOCK_OOR); |
|
1290 |
break; |
|
1291 |
} |
|
1292 | 1316 |
ide_atapi_cmd_read(s, lba, nb_sectors, 2048); |
1293 | 1317 |
} |
1294 | 1318 |
break; |
... | ... | |
1296 | 1320 |
{ |
1297 | 1321 |
int nb_sectors, lba, transfer_request; |
1298 | 1322 |
|
1299 |
if (!bdrv_is_inserted(s->bs)) { |
|
1300 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
1301 |
ASC_MEDIUM_NOT_PRESENT); |
|
1302 |
break; |
|
1303 |
} |
|
1304 | 1323 |
nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; |
1305 | 1324 |
lba = ube32_to_cpu(packet + 2); |
1306 | 1325 |
if (nb_sectors == 0) { |
1307 | 1326 |
ide_atapi_cmd_ok(s); |
1308 | 1327 |
break; |
1309 | 1328 |
} |
1310 |
if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { |
|
1311 |
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
|
1312 |
ASC_LOGICAL_BLOCK_OOR); |
|
1313 |
break; |
|
1314 |
} |
|
1315 | 1329 |
transfer_request = packet[9]; |
1316 | 1330 |
switch(transfer_request & 0xf8) { |
1317 | 1331 |
case 0x00: |
... | ... | |
1336 | 1350 |
case GPCMD_SEEK: |
1337 | 1351 |
{ |
1338 | 1352 |
int lba; |
1339 |
if (!bdrv_is_inserted(s->bs)) { |
|
1353 |
int64_t total_sectors; |
|
1354 |
|
|
1355 |
bdrv_get_geometry(s->bs, &total_sectors); |
|
1356 |
total_sectors >>= 2; |
|
1357 |
if (total_sectors <= 0) { |
|
1340 | 1358 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
1341 | 1359 |
ASC_MEDIUM_NOT_PRESENT); |
1342 | 1360 |
break; |
1343 | 1361 |
} |
1344 | 1362 |
lba = ube32_to_cpu(packet + 2); |
1345 |
if (((int64_t)lba << 2) > s->nb_sectors) {
|
|
1363 |
if (lba >= total_sectors) {
|
|
1346 | 1364 |
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
1347 | 1365 |
ASC_LOGICAL_BLOCK_OOR); |
1348 | 1366 |
break; |
... | ... | |
1358 | 1376 |
|
1359 | 1377 |
if (eject && !start) { |
1360 | 1378 |
/* eject the disk */ |
1361 |
bdrv_close(s->bs); |
|
1379 |
bdrv_eject(s->bs, 1); |
|
1380 |
} else if (eject && start) { |
|
1381 |
/* close the tray */ |
|
1382 |
bdrv_eject(s->bs, 0); |
|
1362 | 1383 |
} |
1363 | 1384 |
ide_atapi_cmd_ok(s); |
1364 | 1385 |
} |
... | ... | |
1379 | 1400 |
case GPCMD_READ_TOC_PMA_ATIP: |
1380 | 1401 |
{ |
1381 | 1402 |
int format, msf, start_track, len; |
1403 |
int64_t total_sectors; |
|
1382 | 1404 |
|
1383 |
if (!bdrv_is_inserted(s->bs)) { |
|
1405 |
bdrv_get_geometry(s->bs, &total_sectors); |
|
1406 |
total_sectors >>= 2; |
|
1407 |
if (total_sectors <= 0) { |
|
1384 | 1408 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
1385 | 1409 |
ASC_MEDIUM_NOT_PRESENT); |
1386 | 1410 |
break; |
... | ... | |
1391 | 1415 |
start_track = packet[6]; |
1392 | 1416 |
switch(format) { |
1393 | 1417 |
case 0: |
1394 |
len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track);
|
|
1418 |
len = cdrom_read_toc(total_sectors, buf, msf, start_track);
|
|
1395 | 1419 |
if (len < 0) |
1396 | 1420 |
goto error_cmd; |
1397 | 1421 |
ide_atapi_cmd_reply(s, len, max_len); |
... | ... | |
1405 | 1429 |
ide_atapi_cmd_reply(s, 12, max_len); |
1406 | 1430 |
break; |
1407 | 1431 |
case 2: |
1408 |
len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track);
|
|
1432 |
len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
|
|
1409 | 1433 |
if (len < 0) |
1410 | 1434 |
goto error_cmd; |
1411 | 1435 |
ide_atapi_cmd_reply(s, len, max_len); |
... | ... | |
1419 | 1443 |
} |
1420 | 1444 |
break; |
1421 | 1445 |
case GPCMD_READ_CDVD_CAPACITY: |
1422 |
if (!bdrv_is_inserted(s->bs)) { |
|
1423 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
1424 |
ASC_MEDIUM_NOT_PRESENT); |
|
1425 |
break; |
|
1446 |
{ |
|
1447 |
int64_t total_sectors; |
|
1448 |
|
|
1449 |
bdrv_get_geometry(s->bs, &total_sectors); |
|
1450 |
total_sectors >>= 2; |
|
1451 |
if (total_sectors <= 0) { |
|
1452 |
ide_atapi_cmd_error(s, SENSE_NOT_READY, |
|
1453 |
ASC_MEDIUM_NOT_PRESENT); |
|
1454 |
break; |
|
1455 |
} |
|
1456 |
/* NOTE: it is really the number of sectors minus 1 */ |
|
1457 |
cpu_to_ube32(buf, total_sectors - 1); |
|
1458 |
cpu_to_ube32(buf + 4, 2048); |
|
1459 |
ide_atapi_cmd_reply(s, 8, 8); |
|
1426 | 1460 |
} |
1427 |
/* NOTE: it is really the number of sectors minus 1 */ |
|
1428 |
cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); |
|
1429 |
cpu_to_ube32(buf + 4, 2048); |
|
1430 |
ide_atapi_cmd_reply(s, 8, 8); |
|
1431 | 1461 |
break; |
1432 | 1462 |
case GPCMD_INQUIRY: |
1433 | 1463 |
max_len = packet[4]; |
... | ... | |
1451 | 1481 |
} |
1452 | 1482 |
} |
1453 | 1483 |
|
1454 |
/* called when the inserted state of the media has changed */ |
|
1455 |
static void cdrom_change_cb(void *opaque) |
|
1456 |
{ |
|
1457 |
IDEState *s = opaque; |
|
1458 |
int64_t nb_sectors; |
|
1459 |
|
|
1460 |
/* XXX: send interrupt too */ |
|
1461 |
bdrv_get_geometry(s->bs, &nb_sectors); |
|
1462 |
s->nb_sectors = nb_sectors; |
|
1463 |
} |
|
1464 |
|
|
1465 | 1484 |
static void ide_cmd_lba48_transform(IDEState *s, int lba48) |
1466 | 1485 |
{ |
1467 | 1486 |
s->lba48 = lba48; |
... | ... | |
2092 | 2111 |
} |
2093 | 2112 |
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { |
2094 | 2113 |
s->is_cdrom = 1; |
2095 |
bdrv_set_change_cb(s->bs, cdrom_change_cb, s); |
|
2096 | 2114 |
} |
2097 | 2115 |
} |
2098 | 2116 |
s->drive_serial = drive_serial++; |
Also available in: Unified diff