Commit 66c6ef7678939f2119eb649074babf5d5b2666f6
1 parent
ea185bbd
better support of removable media
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
69 additions
and
51 deletions
hw/ide.c
| ... | ... | @@ -943,26 +943,44 @@ static void cd_data_to_raw(uint8_t *buf, int lba) |
| 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,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) |
| 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,6 +1093,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) |
| 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,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) |
| 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,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,17 +1481,6 @@ static void ide_atapi_cmd(IDEState *s) |
| 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,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, |
| 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++; | ... | ... |